private void CreateBitmapContexts(Data data)
            {
                m_bitmapContexts = new BitmapContext[data.bitmaps.Length];
                for (int i = 0; i < data.bitmaps.Length; ++i) {
                Format.Bitmap bitmap = data.bitmaps[i];
                // Ignore null texture
                if (bitmap.textureFragmentId == -1)
                continue;
                int bitmapExId = -i - 1;
                Format.BitmapEx bitmapEx = new Format.BitmapEx();
                bitmapEx.matrixId = bitmap.matrixId;
                bitmapEx.textureFragmentId = bitmap.textureFragmentId;
                bitmapEx.u = 0;
                bitmapEx.v = 0;
                bitmapEx.w = 1;
                bitmapEx.h = 1;
                m_bitmapContexts[i] =
                new BitmapContext(this, data, bitmapEx, bitmapExId);
                }

                m_bitmapExContexts = new BitmapContext[data.bitmapExs.Length];
                for (int i = 0; i < data.bitmapExs.Length; ++i) {
                Format.BitmapEx bitmapEx = data.bitmapExs[i];
                // Ignore null texture
                if (bitmapEx.textureFragmentId == -1)
                continue;
                m_bitmapExContexts[i] = new BitmapContext(this, data, bitmapEx, i);
                }
            }
        public static IEnumerable<Color> GetMostPopularColors(BitmapContext context, int k)
        {
            try
            {
                unsafe
                {
                    Dictionary<Color, int> colorsDictionary = new Dictionary<Color, int>();

                    for (int i = 0; i < context.Width; i++)
                    {
                        for (int j = 0; j < context.Height; j++)
                        {
                            var c = context.Pixels[j*context.Width + i];
                            byte a = (byte) (c >> 24);

                            // Prevent division by zero
                            int ai = a;
                            if (ai == 0)
                            {
                                ai = 1;
                            }

                            ai = ((255 << 8)/ai);

                            var color = Color.FromArgb(
                                a,
                                (byte) ((((c >> 16) & 0xFF)*ai) >> 8),
                                (byte) ((((c >> 8) & 0xFF)*ai) >> 8),
                                (byte) ((((c & 0xFF)*ai) >> 8)));

                            if (colorsDictionary.ContainsKey(color))
                            {
                                colorsDictionary[color]++;
                            }
                            else
                            {
                                colorsDictionary[color] = 1;
                            }
                        }
                    }

                    return colorsDictionary.OrderByDescending(b => b.Value).Select(b => b.Key).Take(k);
                }
            }
            catch (AccessViolationException)
            {
                MessageBox.Show("Tried to access protected memory. Try reloading picture.");
            }

            return null;
        }
Beispiel #3
0
        private void DrawBodyPolygon(BitmapContext ctx, Body body)
        {
            var isStatic = body.IgnoresGravity;

            var pts = new int[body.Shape.Vertexes.Count() * 2 + 2];

            var pos = body.State.Position;

            int i = 0;

            foreach (var v in body.Shape.Vertexes)
            {
                var vr = Vector2D.Rotate(pos.Angular, v);
                pts[i] = (int)(vr.X + pos.X); pts[i + 1] = (int)(vr.Y + pos.Y);
                i += 2;
            }
            pts[i] = pts[0]; pts[i + 1] = pts[1];

            ctx.WriteableBitmap.FillPolygon(pts, isStatic ? _statBodyColor : _dynBodyColor);
        }
Beispiel #4
0
 public BitmapRenderer(LWF lwf, BitmapContext context)
     : base(lwf)
 {
     m_context = context;
     m_matrix = new Matrix(0, 0, 0, 0, 0, 0);
     m_matrixForRender = new Matrix4x4();
     m_colorMult = new UnityEngine.Color();
     m_colorAdd = new UnityEngine.Color();
     m_z = -1;
     m_updated = false;
 }
        /// <summary>
        /// Draws an anti-aliased, alpha-blended, colored line by connecting two points using Wu's antialiasing algorithm
        /// Uses the pixels array and the width directly for best performance.
        /// </summary>
        /// <param name="context">An array containing the pixels as int RGBA value.</param>
        /// <param name="pixelWidth">The width of one scanline in the pixels array.</param>
        /// <param name="pixelHeight">The height of the bitmap.</param>
        /// <param name="x1">The x0.</param>
        /// <param name="y1">The y0.</param>
        /// <param name="x2">The x1.</param>
        /// <param name="y2">The y1.</param>
        /// <param name="sa">Alpha color component</param>
        /// <param name="sr">Premultiplied red color component</param>
        /// <param name="sg">Premultiplied green color component</param>
        /// <param name="sb">Premultiplied blue color component</param>
        public static void DrawLineWu(BitmapContext context, int pixelWidth, int pixelHeight, int x1, int y1, int x2, int y2, int sa, int sr, int sg, int sb)
        {
            // Perform cohen-sutherland clipping if either point is out of the viewport
            if (!CohenSutherlandLineClip(new Rect(0, 0, pixelWidth, pixelHeight), ref x1, ref y1, ref x2, ref y2)) return;

            var pixels = context.Pixels;

            const ushort INTENSITY_BITS = 8;
            const short NUM_LEVELS = 1 << INTENSITY_BITS; // 256
            // mask used to compute 1-value by doing (value XOR mask)
            const ushort WEIGHT_COMPLEMENT_MASK = NUM_LEVELS - 1; // 255
            // # of bits by which to shift ErrorAcc to get intensity level 
            const ushort INTENSITY_SHIFT = (ushort)(16 - INTENSITY_BITS); // 8

            ushort ErrorAdj, ErrorAcc;
            ushort ErrorAccTemp, Weighting;
            short DeltaX, DeltaY, XDir;
            int tmp;
            // ensure line runs from top to bottom
            if (y1 > y2)
            {
                tmp = y1; y1 = y2; y2 = tmp;
                tmp = x1; x1 = x2; x2 = tmp;
            }

            // draw initial pixel, which is always intersected by line to it's at 100% intensity
            pixels[y1 * pixelWidth + x1] = AlphaBlend(sa, sr, sg, sb, pixels[y1 * pixelWidth + x1]);
            //bitmap.SetPixel(X0, Y0, BaseColor);

            DeltaX = (short)(x2 - x1);
            if (DeltaX >= 0)
            {
                XDir = 1;
            }
            else
            {
                XDir = -1;
                DeltaX = (short)-DeltaX; /* make DeltaX positive */
            }

            // Special-case horizontal, vertical, and diagonal lines, which
            // require no weighting because they go right through the center of
            // every pixel; also avoids division by zero later
            DeltaY = (short)(y2 - y1);
            if (DeltaY == 0) // if horizontal line
            {
                while (DeltaX-- != 0)
                {
                    x1 += XDir;
                    pixels[y1 * pixelWidth + x1] = AlphaBlend(sa, sr, sg, sb, pixels[y1 * pixelWidth + x1]);
                }
                return;
            }

            if (DeltaX == 0) // if vertical line 
            {
                do
                {
                    y1++;
                    pixels[y1 * pixelWidth + x1] = AlphaBlend(sa, sr, sg, sb, pixels[y1 * pixelWidth + x1]);
                } while (--DeltaY != 0);
                return;
            }

            if (DeltaX == DeltaY) // diagonal line
            {
                do
                {
                    x1 += XDir;
                    y1++;
                    pixels[y1 * pixelWidth + x1] = AlphaBlend(sa, sr, sg, sb, pixels[y1 * pixelWidth + x1]);
                } while (--DeltaY != 0);
                return;
            }

            // Line is not horizontal, diagonal, or vertical
            ErrorAcc = 0;  // initialize the line error accumulator to 0

            // Is this an X-major or Y-major line? 
            if (DeltaY > DeltaX)
            {
                // Y-major line; calculate 16-bit fixed-point fractional part of a
                // pixel that X advances each time Y advances 1 pixel, truncating the
                // result so that we won't overrun the endpoint along the X axis 
                ErrorAdj = (ushort)(((ulong)DeltaX << 16) / (ulong)DeltaY);

                // Draw all pixels other than the first and last 
                while (--DeltaY != 0)
                {
                    ErrorAccTemp = ErrorAcc;   // remember current accumulated error 
                    ErrorAcc += ErrorAdj;      // calculate error for next pixel 
                    if (ErrorAcc <= ErrorAccTemp)
                    {
                        // The error accumulator turned over, so advance the X coord */
                        x1 += XDir;
                    }
                    y1++; /* Y-major, so always advance Y */
                    // The IntensityBits most significant bits of ErrorAcc give us the
                    // intensity weighting for this pixel, and the complement of the
                    // weighting for the paired pixel 
                    Weighting = (ushort)(ErrorAcc >> INTENSITY_SHIFT);

                    int weight = Weighting ^ WEIGHT_COMPLEMENT_MASK;
                    pixels[y1 * pixelWidth + x1] = AlphaBlend(sa, (sr * weight) >> 8, (sg * weight) >> 8, (sb * weight) >> 8, pixels[y1 * pixelWidth + x1]);

                    weight = Weighting;
                    pixels[y1 * pixelWidth + x1 + XDir] = AlphaBlend(sa, (sr * weight) >> 8, (sg * weight) >> 8, (sb * weight) >> 8, pixels[y1 * pixelWidth + x1 + XDir]);

                    //bitmap.SetPixel(X0, Y0, 255 - (BaseColor + Weighting));
                    //bitmap.SetPixel(X0 + XDir, Y0, 255 - (BaseColor + (Weighting ^ WeightingComplementMask)));
                }

                // Draw the final pixel, which is always exactly intersected by the line and so needs no weighting
                pixels[y2 * pixelWidth + x2] = AlphaBlend(sa, sr, sg, sb, pixels[y2 * pixelWidth + x2]);
                //bitmap.SetPixel(X1, Y1, BaseColor);
                return;
            }
            // It's an X-major line; calculate 16-bit fixed-point fractional part of a
            // pixel that Y advances each time X advances 1 pixel, truncating the
            // result to avoid overrunning the endpoint along the X axis */
            ErrorAdj = (ushort)(((ulong)DeltaY << 16) / (ulong)DeltaX);

            // Draw all pixels other than the first and last 
            while (--DeltaX != 0)
            {
                ErrorAccTemp = ErrorAcc;   // remember current accumulated error 
                ErrorAcc += ErrorAdj;      // calculate error for next pixel 
                if (ErrorAcc <= ErrorAccTemp) // if error accumulator turned over
                {
                    // advance the Y coord
                    y1++;
                }
                x1 += XDir; // X-major, so always advance X 
                // The IntensityBits most significant bits of ErrorAcc give us the
                // intensity weighting for this pixel, and the complement of the
                // weighting for the paired pixel 
                Weighting = (ushort)(ErrorAcc >> INTENSITY_SHIFT);

                int weight = Weighting ^ WEIGHT_COMPLEMENT_MASK;
                pixels[y1 * pixelWidth + x1] = AlphaBlend(sa, (sr * weight) >> 8, (sg * weight) >> 8, (sb * weight) >> 8, pixels[y1 * pixelWidth + x1]);

                weight = Weighting;
                pixels[(y1 + 1) * pixelWidth + x1] = AlphaBlend(sa, (sr * weight) >> 8, (sg * weight) >> 8, (sb * weight) >> 8, pixels[(y1 + 1) * pixelWidth + x1]);

                //bitmap.SetPixel(X0, Y0, 255 - (BaseColor + Weighting));
                //bitmap.SetPixel(X0, Y0 + 1,
                //      255 - (BaseColor + (Weighting ^ WeightingComplementMask)));
            }
            // Draw the final pixel, which is always exactly intersected by the line and thus needs no weighting 
            pixels[y2 * pixelWidth + x2] = AlphaBlend(sa, sr, sg, sb, pixels[y2 * pixelWidth + x2]);
            //bitmap.SetPixel(X1, Y1, BaseColor);
        }
        /// <summary>
        /// Draws a colored line by connecting two points using an optimized DDA. 
        /// Uses the pixels array and the width directly for best performance.
        /// </summary>
        /// <param name="context">The context containing the pixels as int RGBA value.</param>
        /// <param name="pixelWidth">The width of one scanline in the pixels array.</param>
        /// <param name="pixelHeight">The height of the bitmap.</param>
        /// <param name="x1">The x-coordinate of the start point.</param>
        /// <param name="y1">The y-coordinate of the start point.</param>
        /// <param name="x2">The x-coordinate of the end point.</param>
        /// <param name="y2">The y-coordinate of the end point.</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawLine(BitmapContext context, int pixelWidth, int pixelHeight, int x1, int y1, int x2, int y2, int color)
        {
            // Perform cohen-sutherland clipping if either point is out of the viewport
            if (!CohenSutherlandLineClip(new Rect(0, 0, pixelWidth, pixelHeight), ref x1, ref y1, ref x2, ref y2)) return;

            var pixels = context.Pixels;

            // Distance start and end point
            int dx = x2 - x1;
            int dy = y2 - y1;

            const int PRECISION_SHIFT = 8;

            // Determine slope (absolute value)
            int lenX, lenY;
            if (dy >= 0)
            {
                lenY = dy;
            }
            else
            {
                lenY = -dy;
            }

            if (dx >= 0)
            {
                lenX = dx;
            }
            else
            {
                lenX = -dx;
            }

            if (lenX > lenY)
            { // x increases by +/- 1
                if (dx < 0)
                {
                    int t = x1;
                    x1 = x2;
                    x2 = t;
                    t = y1;
                    y1 = y2;
                    y2 = t;
                }

                // Init steps and start
                int incy = (dy << PRECISION_SHIFT) / dx;

                int y1s = y1 << PRECISION_SHIFT;
                int y2s = y2 << PRECISION_SHIFT;
                int hs = pixelHeight << PRECISION_SHIFT;

                if (y1 < y2)
                {
                    if (y1 >= pixelHeight || y2 < 0)
                    {
                        return;
                    }
                    if (y1s < 0)
                    {
                        if (incy == 0)
                        {
                            return;
                        }
                        int oldy1s = y1s;
                        // Find lowest y1s that is greater or equal than 0.
                        y1s = incy - 1 + ((y1s + 1) % incy);
                        x1 += (y1s - oldy1s) / incy;
                    }
                    if (y2s >= hs)
                    {
                        if (incy != 0)
                        {
                            // Find highest y2s that is less or equal than ws - 1.
                            // y2s = y1s + n * incy. Find n.
                            y2s = hs - 1 - (hs - 1 - y1s) % incy;
                            x2 = x1 + (y2s - y1s) / incy;
                        }
                    }
                }
                else
                {
                    if (y2 >= pixelHeight || y1 < 0)
                    {
                        return;
                    }
                    if (y1s >= hs)
                    {
                        if (incy == 0)
                        {
                            return;
                        }
                        int oldy1s = y1s;
                        // Find highest y1s that is less or equal than ws - 1.
                        // y1s = oldy1s + n * incy. Find n.
                        y1s = hs - 1 + (incy - (hs - 1 - oldy1s) % incy);
                        x1 += (y1s - oldy1s) / incy;
                    }
                    if (y2s < 0)
                    {
                        if (incy != 0)
                        {
                            // Find lowest y2s that is greater or equal than 0.
                            // y2s = y1s + n * incy. Find n.
                            y2s = y1s % incy;
                            x2 = x1 + (y2s - y1s) / incy;
                        }
                    }
                }

                if (x1 < 0)
                {
                    y1s -= incy * x1;
                    x1 = 0;
                }
                if (x2 >= pixelWidth)
                {
                    x2 = pixelWidth - 1;
                }

                int ys = y1s;

                // Walk the line!
                int y = ys >> PRECISION_SHIFT;
                int previousY = y;
                int index = x1 + y * pixelWidth;
                int k = incy < 0 ? 1 - pixelWidth : 1 + pixelWidth;
                for (int x = x1; x <= x2; ++x)
                {
                    pixels[index] = color;
                    ys += incy;
                    y = ys >> PRECISION_SHIFT;
                    if (y != previousY)
                    {
                        previousY = y;
                        index += k;
                    }
                    else
                    {
                        ++index;
                    }
                }
            }
            else
            {
                // Prevent division by zero
                if (lenY == 0)
                {
                    return;
                }
                if (dy < 0)
                {
                    int t = x1;
                    x1 = x2;
                    x2 = t;
                    t = y1;
                    y1 = y2;
                    y2 = t;
                }

                // Init steps and start
                int x1s = x1 << PRECISION_SHIFT;
                int x2s = x2 << PRECISION_SHIFT;
                int ws = pixelWidth << PRECISION_SHIFT;

                int incx = (dx << PRECISION_SHIFT) / dy;

                if (x1 < x2)
                {
                    if (x1 >= pixelWidth || x2 < 0)
                    {
                        return;
                    }
                    if (x1s < 0)
                    {
                        if (incx == 0)
                        {
                            return;
                        }
                        int oldx1s = x1s;
                        // Find lowest x1s that is greater or equal than 0.
                        x1s = incx - 1 + ((x1s + 1) % incx);
                        y1 += (x1s - oldx1s) / incx;
                    }
                    if (x2s >= ws)
                    {
                        if (incx != 0)
                        {
                            // Find highest x2s that is less or equal than ws - 1.
                            // x2s = x1s + n * incx. Find n.
                            x2s = ws - 1 - (ws - 1 - x1s) % incx;
                            y2 = y1 + (x2s - x1s) / incx;
                        }
                    }
                }
                else
                {
                    if (x2 >= pixelWidth || x1 < 0)
                    {
                        return;
                    }
                    if (x1s >= ws)
                    {
                        if (incx == 0)
                        {
                            return;
                        }
                        int oldx1s = x1s;
                        // Find highest x1s that is less or equal than ws - 1.
                        // x1s = oldx1s + n * incx. Find n.
                        x1s = ws - 1 + (incx - (ws - 1 - oldx1s) % incx);
                        y1 += (x1s - oldx1s) / incx;
                    }
                    if (x2s < 0)
                    {
                        if (incx != 0)
                        {
                            // Find lowest x2s that is greater or equal than 0.
                            // x2s = x1s + n * incx. Find n.
                            x2s = x1s % incx;
                            y2 = y1 + (x2s - x1s) / incx;
                        }
                    }
                }

                if (y1 < 0)
                {
                    x1s -= incx * y1;
                    y1 = 0;
                }
                if (y2 >= pixelHeight)
                {
                    y2 = pixelHeight - 1;
                }

                int index = x1s;
                int indexBaseValue = y1 * pixelWidth;

                // Walk the line!
                var inc = (pixelWidth << PRECISION_SHIFT) + incx;
                for (int y = y1; y <= y2; ++y)
                {
                    pixels[indexBaseValue + (index >> PRECISION_SHIFT)] = color;
                    index += inc;
                }
            }
        }
        /// <summary> 
        /// Draws an anti-aliased line, using an optimized version of Gupta-Sproull algorithm 
        /// From http://nokola.com/blog/post/2010/10/14/Anti-aliased-Lines-And-Optimizing-Code-for-Windows-Phone-7e28093First-Look.aspx
        /// <param name="context">The context containing the pixels as int RGBA value.</param>
        /// <param name="pixelWidth">The width of one scanline in the pixels array.</param>
        /// <param name="pixelHeight">The height of the bitmap.</param>
        /// <param name="x1">The x-coordinate of the start point.</param>
        /// <param name="y1">The y-coordinate of the start point.</param>
        /// <param name="x2">The x-coordinate of the end point.</param>
        /// <param name="y2">The y-coordinate of the end point.</param>
        /// <param name="color">The color for the line.</param>
        /// </summary> 
        public static void DrawLineAa(BitmapContext context, int pixelWidth, int pixelHeight, int x1, int y1, int x2, int y2, int color)
        {
            if ((x1 == x2) && (y1 == y2)) return; // edge case causing invDFloat to overflow, found by Shai Rubinshtein

            // Perform cohen-sutherland clipping if either point is out of the viewport
            if (!CohenSutherlandLineClip(new Rect(0, 0, pixelWidth, pixelHeight), ref x1, ref y1, ref x2, ref y2)) return;

            if (x1 < 1) x1 = 1;
            if (x1 > pixelWidth - 2) x1 = pixelWidth - 2;
            if (y1 < 1) y1 = 1;
            if (y1 > pixelHeight - 2) y1 = pixelHeight - 2;

            if (x2 < 1) x2 = 1;
            if (x2 > pixelWidth - 2) x2 = pixelWidth - 2;
            if (y2 < 1) y2 = 1;
            if (y2 > pixelHeight - 2) y2 = pixelHeight - 2;

            var addr = y1 * pixelWidth + x1;
            var dx = x2 - x1;
            var dy = y2 - y1;

            int du;
            int dv;
            int u;
            int v;
            int uincr;
            int vincr;

            // Extract color
            var a = (color >> 24) & 0xFF;
            var srb = (uint)(color & 0x00FF00FF);
            var sg = (uint)((color >> 8) & 0xFF);

            // By switching to (u,v), we combine all eight octants 
            int adx = dx, ady = dy;
            if (dx < 0) adx = -dx;
            if (dy < 0) ady = -dy;

            if (adx > ady)
            {
                du = adx;
                dv = ady;
                u = x2;
                v = y2;
                uincr = 1;
                vincr = pixelWidth;
                if (dx < 0) uincr = -uincr;
                if (dy < 0) vincr = -vincr;
            }
            else
            {
                du = ady;
                dv = adx;
                u = y2;
                v = x2;
                uincr = pixelWidth;
                vincr = 1;
                if (dy < 0) uincr = -uincr;
                if (dx < 0) vincr = -vincr;
            }

            var uend = u + du;
            var d = (dv << 1) - du;        // Initial value as in Bresenham's 
            var incrS = dv << 1;    // &#916;d for straight increments 
            var incrD = (dv - du) << 1;    // &#916;d for diagonal increments

            var invDFloat = 1.0 / (4.0 * Math.Sqrt(du * du + dv * dv));   // Precomputed inverse denominator 
            var invD2DuFloat = 0.75 - 2.0 * (du * invDFloat);   // Precomputed constant

            const int PRECISION_SHIFT = 10; // result distance should be from 0 to 1 << PRECISION_SHIFT, mapping to a range of 0..1 
            const int PRECISION_MULTIPLIER = 1 << PRECISION_SHIFT;
            var invD = (int)(invDFloat * PRECISION_MULTIPLIER);
            var invD2Du = (int)(invD2DuFloat * PRECISION_MULTIPLIER * a);
            var zeroDot75 = (int)(0.75 * PRECISION_MULTIPLIER * a);

            var invDMulAlpha = invD * a;
            var duMulInvD = du * invDMulAlpha; // used to help optimize twovdu * invD 
            var dMulInvD = d * invDMulAlpha; // used to help optimize twovdu * invD 
            //int twovdu = 0;    // Numerator of distance; starts at 0 
            var twovduMulInvD = 0; // since twovdu == 0 
            var incrSMulInvD = incrS * invDMulAlpha;
            var incrDMulInvD = incrD * invDMulAlpha;

            do
            {
                AlphaBlendNormalOnPremultiplied(context, addr, (zeroDot75 - twovduMulInvD) >> PRECISION_SHIFT, srb, sg);
                AlphaBlendNormalOnPremultiplied(context, addr + vincr, (invD2Du + twovduMulInvD) >> PRECISION_SHIFT, srb, sg);
                AlphaBlendNormalOnPremultiplied(context, addr - vincr, (invD2Du - twovduMulInvD) >> PRECISION_SHIFT, srb, sg);

                if (d < 0)
                {
                    // choose straight (u direction) 
                    twovduMulInvD = dMulInvD + duMulInvD;
                    d += incrS;
                    dMulInvD += incrSMulInvD;
                }
                else
                {
                    // choose diagonal (u+v direction) 
                    twovduMulInvD = dMulInvD - duMulInvD;
                    d += incrD;
                    dMulInvD += incrDMulInvD;
                    v++;
                    addr += vincr;
                }
                u++;
                addr += uincr;
            } while (u < uend);
        }
      /// <summary>
      /// Creates a new resized bitmap.
      /// </summary>
      /// <param name="srcContext">The source context.</param>
      /// <param name="widthSource">The width of the source pixels.</param>
      /// <param name="heightSource">The height of the source pixels.</param>
      /// <param name="width">The new desired width.</param>
      /// <param name="height">The new desired height.</param>
      /// <param name="interpolation">The interpolation method that should be used.</param>
      /// <returns>A new bitmap that is a resized version of the input.</returns>
      public static int[] Resize(BitmapContext srcContext, int widthSource, int heightSource, int width, int height, Interpolation interpolation)
      {
         var pixels = srcContext.Pixels;
         var pd = new int[width * height];
         var xs = (float)widthSource / width;
         var ys = (float)heightSource / height;

         float fracx, fracy, ifracx, ifracy, sx, sy, l0, l1, rf, gf, bf;
         int c, x0, x1, y0, y1;
         byte c1a, c1r, c1g, c1b, c2a, c2r, c2g, c2b, c3a, c3r, c3g, c3b, c4a, c4r, c4g, c4b;
         byte a, r, g, b;

         // Nearest Neighbor
         if (interpolation == Interpolation.NearestNeighbor)
         {
            var srcIdx = 0;
            for (var y = 0; y < height; y++)
            {
               for (var x = 0; x < width; x++)
               {
                  sx = x * xs;
                  sy = y * ys;
                  x0 = (int)sx;
                  y0 = (int)sy;

                  pd[srcIdx++] = pixels[y0 * widthSource + x0];
               }
            }
         }

            // Bilinear
         else if (interpolation == Interpolation.Bilinear)
         {
            var srcIdx = 0;
            for (var y = 0; y < height; y++)
            {
               for (var x = 0; x < width; x++)
               {
                  sx = x * xs;
                  sy = y * ys;
                  x0 = (int)sx;
                  y0 = (int)sy;

                  // Calculate coordinates of the 4 interpolation points
                  fracx = sx - x0;
                  fracy = sy - y0;
                  ifracx = 1f - fracx;
                  ifracy = 1f - fracy;
                  x1 = x0 + 1;
                  if (x1 >= widthSource)
                  {
                     x1 = x0;
                  }
                  y1 = y0 + 1;
                  if (y1 >= heightSource)
                  {
                     y1 = y0;
                  }


                  // Read source color
                  c = pixels[y0 * widthSource + x0];
                  c1a = (byte)(c >> 24);
                  c1r = (byte)(c >> 16);
                  c1g = (byte)(c >> 8);
                  c1b = (byte)(c);

                  c = pixels[y0 * widthSource + x1];
                  c2a = (byte)(c >> 24);
                  c2r = (byte)(c >> 16);
                  c2g = (byte)(c >> 8);
                  c2b = (byte)(c);

                  c = pixels[y1 * widthSource + x0];
                  c3a = (byte)(c >> 24);
                  c3r = (byte)(c >> 16);
                  c3g = (byte)(c >> 8);
                  c3b = (byte)(c);

                  c = pixels[y1 * widthSource + x1];
                  c4a = (byte)(c >> 24);
                  c4r = (byte)(c >> 16);
                  c4g = (byte)(c >> 8);
                  c4b = (byte)(c);


                  // Calculate colors
                  // Alpha
                  l0 = ifracx * c1a + fracx * c2a;
                  l1 = ifracx * c3a + fracx * c4a;
                  a = (byte)(ifracy * l0 + fracy * l1);

                  // Red
                  l0 = ifracx * c1r * c1a + fracx * c2r * c2a;
                  l1 = ifracx * c3r * c3a + fracx * c4r * c4a;
                  rf = ifracy * l0 + fracy * l1;

                  // Green
                  l0 = ifracx * c1g * c1a + fracx * c2g * c2a;
                  l1 = ifracx * c3g * c3a + fracx * c4g * c4a;
                  gf = ifracy * l0 + fracy * l1;

                  // Blue
                  l0 = ifracx * c1b * c1a + fracx * c2b * c2a;
                  l1 = ifracx * c3b * c3a + fracx * c4b * c4a;
                  bf = ifracy * l0 + fracy * l1;

                  // Divide by alpha
                  if (a > 0)
                  {
                     rf = rf / a;
                     gf = gf / a;
                     bf = bf / a;
                  }

                  // Cast to byte
                  r = (byte)rf;
                  g = (byte)gf;
                  b = (byte)bf;

                  // Write destination
                  pd[srcIdx++] = (a << 24) | (r << 16) | (g << 8) | b;
               }
            }
         }
         return pd;
      }
        private static void DrawHorizontally(BitmapContext context, int x1, int x2, int y, int dotSpace, int dotLength, int color) {
            int width = context.Width;
            int height = context.Height;            
            var pixels = context.Pixels;
            bool on = true;
            int spaceCnt = 0;
            for (int i = x1; i <= x2; i++) {
                if (i < 1) {
                    continue;
                }
                if (i >= width) {
                    break;
                }
                if (y >= height) {
                    break;
                }

                if (on) {
                    //bmp.SetPixel(i, y, color);
                    //var idx = GetIndex(i, y, width);
                    var idx = (y - 1) * width + i - 1;
                    pixels[idx] = color;
                    on = i % dotLength != 0;
                    spaceCnt = 0;
                } else {
                    spaceCnt++;
                    on = spaceCnt % dotSpace == 0;
                }
                //System.Diagnostics.Debug.WriteLine($"{i},{y}, on = {on}");
            }
        }
 private static void AddBodyToContext(IBody body, BitmapContext context, Color boneColor, Color jointColor)
 {
     DrawBonesAndJoints(body, context, boneColor, jointColor);
     RenderClippedEdges(body, context);
 }
 public static unsafe void BlockCopy(BitmapContext src, int srcOffset, BitmapContext dest, int destOffset, int count)
 {
     NativeMethods.CopyUnmanagedMemory((byte *)src.Pixels, srcOffset, (byte *)dest.Pixels, destOffset, count);
 }
        private static void AALineQ1(int width, int height, BitmapContext context, int x1, int y1, int x2, int y2, Int32 color, bool minEdge, bool leftEdge)
        {
            Byte off = 0;

            if (minEdge)
            {
                off = 0xff;
            }

            if (x1 == x2)
            {
                return;
            }
            if (y1 == y2)
            {
                return;
            }

            var buffer = context.Pixels;

            if (y1 > y2)
            {
                Swap(ref x1, ref x2);
                Swap(ref y1, ref y2);
            }

            var deltax = (x2 - x1);
            var deltay = (y2 - y1);

            if (x1 > x2)
            {
                deltax = (x1 - x2);
            }

            var x = x1;
            var y = y1;

            UInt16 m = 0;

            if (deltax > deltay)
            {
                m = (ushort)(((deltay << 16) / deltax));
            }
            else
            {
                m = (ushort)(((deltax << 16) / deltay));
            }

            UInt16 e = 0;

            var a = (byte)((color & 0xff000000) >> 24);
            var r = (byte)((color & 0x00ff0000) >> 16);
            var g = (byte)((color & 0x0000ff00) >> 8);
            var b = (byte)((color & 0x000000ff) >> 0);

            Byte rs, gs, bs;
            Byte rd, gd, bd;

            Int32 d;

            var ta = a;

            e = 0;

            if (deltax >= deltay)
            {
                while (deltax-- != 0)
                {
                    if ((UInt16)(e + m) <= e) // Roll
                    {
                        y++;
                    }

                    e += m;

                    if (x1 < x2)
                    {
                        x++;
                    }
                    else
                    {
                        x--;
                    }

                    if (y < 0 || y >= height)
                    {
                        continue;
                    }

                    if (leftEdge)
                    {
                        leftEdgeX[y] = Math.Max(x + 1, leftEdgeX[y]);
                    }
                    else
                    {
                        rightEdgeX[y] = Math.Min(x - 1, rightEdgeX[y]);
                    }

                    if (x < 0 || x >= width)
                    {
                        continue;
                    }

                    //

                    ta = (byte)((a * (UInt16)(((((UInt16)(e >> 8))) ^ off))) >> 8);

                    rs = r;
                    gs = g;
                    bs = b;

                    d = buffer[y * width + x];

                    rd = (byte)((d & 0x00ff0000) >> 16);
                    gd = (byte)((d & 0x0000ff00) >> 8);
                    bd = (byte)((d & 0x000000ff) >> 0);

                    rd = (byte)((rs * ta + rd * (0xff - ta)) >> 8);
                    gd = (byte)((gs * ta + gd * (0xff - ta)) >> 8);
                    bd = (byte)((bs * ta + bd * (0xff - ta)) >> 8);

                    buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0);

                    //
                }
            }
            else
            {
                off ^= 0xff;

                while (--deltay != 0)
                {
                    if ((UInt16)(e + m) <= e) // Roll
                    {
                        if (x1 < x2)
                        {
                            x++;
                        }
                        else
                        {
                            x--;
                        }
                    }

                    e += m;

                    y++;

                    if (x < 0 || x >= width)
                    {
                        continue;
                    }
                    if (y < 0 || y >= height)
                    {
                        continue;
                    }

                    //

                    ta = (byte)((a * (UInt16)(((((UInt16)(e >> 8))) ^ off))) >> 8);

                    rs = r;
                    gs = g;
                    bs = b;

                    d = buffer[y * width + x];

                    rd = (byte)((d & 0x00ff0000) >> 16);
                    gd = (byte)((d & 0x0000ff00) >> 8);
                    bd = (byte)((d & 0x000000ff) >> 0);

                    rd = (byte)((rs * ta + rd * (0xff - ta)) >> 8);
                    gd = (byte)((gs * ta + gd * (0xff - ta)) >> 8);
                    bd = (byte)((bs * ta + bd * (0xff - ta)) >> 8);

                    buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0);

                    if (leftEdge)
                    {
                        leftEdgeX[y] = x + 1;
                    }
                    else
                    {
                        rightEdgeX[y] = x - 1;
                    }
                }
            }
        }
        /// <summary>
        /// Renders a bitmap using any affine transformation and transparency into this bitmap
        /// Unlike Silverlight's Render() method, this one uses 2-3 times less memory, and is the same or better quality
        /// The algorithm is simple dx/dy (bresenham-like) step by step painting, optimized with fixed point and fast bilinear filtering
        /// It's used in Fantasia Painter for drawing stickers and 3D objects on screen
        /// </summary>
        /// <param name="bmp">Destination bitmap.</param>
        /// <param name="source">The source WriteableBitmap.</param>
        /// <param name="shouldClear">If true, the the destination bitmap will be set to all clear (0) before rendering.</param>
        /// <param name="opacity">opacity of the source bitmap to render, between 0 and 1 inclusive</param>
        /// <param name="transform">Transformation to apply</param>
        public static void BlitRender(this WriteableBitmap bmp, WriteableBitmap source, bool shouldClear = true, float opacity = 1f, GeneralTransform transform = null)
        {
            const int PRECISION_SHIFT = 10;
            const int PRECISION_VALUE = (1 << PRECISION_SHIFT);
            const int PRECISION_MASK  = PRECISION_VALUE - 1;

            using (BitmapContext destContext = bmp.GetBitmapContext())
            {
                if (transform == null)
                {
                    transform = new MatrixTransform();
                }

                var destPixels = destContext.Pixels;
                int destWidth  = destContext.Width;
                int destHeight = destContext.Height;
                var inverse    = transform.Inverse;
                if (shouldClear)
                {
                    destContext.Clear();
                }

                using (BitmapContext sourceContext = source.GetBitmapContext(ReadWriteMode.ReadOnly))
                {
                    var sourcePixels = sourceContext.Pixels;
                    int sourceWidth  = sourceContext.Width;
                    int sourceHeight = sourceContext.Height;

                    Rect sourceRect = new Rect(0, 0, sourceWidth, sourceHeight);
                    Rect destRect   = new Rect(0, 0, destWidth, destHeight);
                    Rect bounds     = transform.TransformBounds(sourceRect);
                    bounds.Intersect(destRect);

                    int startX = (int)bounds.Left;
                    int startY = (int)bounds.Top;
                    int endX   = (int)bounds.Right;
                    int endY   = (int)bounds.Bottom;

#if NETFX_CORE
                    Point zeroZero = inverse.TransformPoint(new Point(startX, startY));
                    Point oneZero  = inverse.TransformPoint(new Point(startX + 1, startY));
                    Point zeroOne  = inverse.TransformPoint(new Point(startX, startY + 1));
#else
                    Point zeroZero = inverse.Transform(new Point(startX, startY));
                    Point oneZero  = inverse.Transform(new Point(startX + 1, startY));
                    Point zeroOne  = inverse.Transform(new Point(startX, startY + 1));
#endif
                    float sourceXf = ((float)zeroZero.X);
                    float sourceYf = ((float)zeroZero.Y);
                    int   dxDx     = (int)((((float)oneZero.X) - sourceXf) * PRECISION_VALUE); // for 1 unit in X coord, how much does X change in source texture?
                    int   dxDy     = (int)((((float)oneZero.Y) - sourceYf) * PRECISION_VALUE); // for 1 unit in X coord, how much does Y change in source texture?
                    int   dyDx     = (int)((((float)zeroOne.X) - sourceXf) * PRECISION_VALUE); // for 1 unit in Y coord, how much does X change in source texture?
                    int   dyDy     = (int)((((float)zeroOne.Y) - sourceYf) * PRECISION_VALUE); // for 1 unit in Y coord, how much does Y change in source texture?

                    int sourceX           = (int)(((float)zeroZero.X) * PRECISION_VALUE);
                    int sourceY           = (int)(((float)zeroZero.Y) * PRECISION_VALUE);
                    int sourceWidthFixed  = sourceWidth << PRECISION_SHIFT;
                    int sourceHeightFixed = sourceHeight << PRECISION_SHIFT;

                    int opacityInt = (int)(opacity * 255);

                    int index = 0;
                    for (int destY = startY; destY < endY; destY++)
                    {
                        index = destY * destWidth + startX;
                        int savedSourceX = sourceX;
                        int savedSourceY = sourceY;

                        for (int destX = startX; destX < endX; destX++)
                        {
                            if ((sourceX >= 0) && (sourceX < sourceWidthFixed) && (sourceY >= 0) && (sourceY < sourceHeightFixed))
                            {
                                // bilinear filtering
                                int xFloor = sourceX >> PRECISION_SHIFT;
                                int yFloor = sourceY >> PRECISION_SHIFT;

                                if (xFloor < 0)
                                {
                                    xFloor = 0;
                                }
                                if (yFloor < 0)
                                {
                                    yFloor = 0;
                                }

                                int xCeil = xFloor + 1;
                                int yCeil = yFloor + 1;

                                if (xCeil >= sourceWidth)
                                {
                                    xFloor = sourceWidth - 1;
                                    xCeil  = 0;
                                }
                                else
                                {
                                    xCeil = 1;
                                }

                                if (yCeil >= sourceHeight)
                                {
                                    yFloor = sourceHeight - 1;
                                    yCeil  = 0;
                                }
                                else
                                {
                                    yCeil = sourceWidth;
                                }

                                int i1 = yFloor * sourceWidth + xFloor;
                                int p1 = sourcePixels[i1];
                                int p2 = sourcePixels[i1 + xCeil];
                                int p3 = sourcePixels[i1 + yCeil];
                                int p4 = sourcePixels[i1 + yCeil + xCeil];

                                int xFrac = sourceX & PRECISION_MASK;
                                int yFrac = sourceY & PRECISION_MASK;

                                // alpha
                                byte a1 = (byte)(p1 >> 24);
                                byte a2 = (byte)(p2 >> 24);
                                byte a3 = (byte)(p3 >> 24);
                                byte a4 = (byte)(p4 >> 24);

                                int  comp1, comp2;
                                byte a;

                                if ((a1 == a2) && (a1 == a3) && (a1 == a4))
                                {
                                    if (a1 == 0)
                                    {
                                        destPixels[index] = 0;

                                        sourceX += dxDx;
                                        sourceY += dxDy;
                                        index++;
                                        continue;
                                    }

                                    a = a1;
                                }
                                else
                                {
                                    comp1 = a1 + ((xFrac * (a2 - a1)) >> PRECISION_SHIFT);
                                    comp2 = a3 + ((xFrac * (a4 - a3)) >> PRECISION_SHIFT);
                                    a     = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT));
                                }

                                // red
                                comp1 = ((byte)(p1 >> 16)) + ((xFrac * (((byte)(p2 >> 16)) - ((byte)(p1 >> 16)))) >> PRECISION_SHIFT);
                                comp2 = ((byte)(p3 >> 16)) + ((xFrac * (((byte)(p4 >> 16)) - ((byte)(p3 >> 16)))) >> PRECISION_SHIFT);
                                byte r = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT));

                                // green
                                comp1 = ((byte)(p1 >> 8)) + ((xFrac * (((byte)(p2 >> 8)) - ((byte)(p1 >> 8)))) >> PRECISION_SHIFT);
                                comp2 = ((byte)(p3 >> 8)) + ((xFrac * (((byte)(p4 >> 8)) - ((byte)(p3 >> 8)))) >> PRECISION_SHIFT);
                                byte g = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT));

                                // blue
                                comp1 = ((byte)p1) + ((xFrac * (((byte)p2) - ((byte)p1))) >> PRECISION_SHIFT);
                                comp2 = ((byte)p3) + ((xFrac * (((byte)p4) - ((byte)p3))) >> PRECISION_SHIFT);
                                byte b = (byte)(comp1 + ((yFrac * (comp2 - comp1)) >> PRECISION_SHIFT));

                                // save updated pixel
                                if (opacityInt != 255)
                                {
                                    a = (byte)((a * opacityInt) >> 8);
                                    r = (byte)((r * opacityInt) >> 8);
                                    g = (byte)((g * opacityInt) >> 8);
                                    b = (byte)((b * opacityInt) >> 8);
                                }
                                destPixels[index] = (a << 24) | (r << 16) | (g << 8) | b;
                            }

                            sourceX += dxDx;
                            sourceY += dxDy;
                            index++;
                        }

                        sourceX = savedSourceX + dyDx;
                        sourceY = savedSourceY + dyDy;
                    }
                }
            }
        }
        private static void RenderClippedEdges(IBody body, BitmapContext context)
        {
            try
            {
                if (body.ClippedEdges.HasFlag(FrameEdges.Bottom))
                {
                    context.WriteableBitmap.FillRectangle(
                        0,
                        (int)_height - (int)_clipBoundsThickness,
                        (int)_width,
                        (int)_height,
                        Colors.Red);
                }

                if (body.ClippedEdges.HasFlag(FrameEdges.Top))
                {
                    context.WriteableBitmap.FillRectangle(
                        0,
                        0,
                        (int)_width,
                        (int)_clipBoundsThickness,
                        Colors.Red);
                }

                if (body.ClippedEdges.HasFlag(FrameEdges.Left))
                {
                    context.WriteableBitmap.FillRectangle(
                        0,
                        0,
                        (int)_clipBoundsThickness,
                        (int)_height,
                        Colors.Red);
                }

                if (body.ClippedEdges.HasFlag(FrameEdges.Right))
                {
                    context.WriteableBitmap.FillRectangle(
                        (int)_width - (int)_clipBoundsThickness,
                        0,
                        (int)_width,
                        (int)_height,
                        Colors.Red);
                }
            }
            catch { }
        }
        private static void DrawBonesAndJoints(IBody body, BitmapContext context, Color boneColor, Color jointColor)
        {
            foreach (var bone in CustomBoneType.DrawnBones)
            {
                DrawBone(body, context, bone, boneColor);
            }

            Color inferredJointColor = jointColor;
            inferredJointColor.A = 128;

            // Render Joints
            foreach (var joint in body.Joints.Values)
            {
                if (joint.TrackingState == TrackingState.NotTracked)
                {
                    continue;
                }

                var point = GetDepthSpacePoint(joint, body.HasMappedDepthPositions);

                context.WriteableBitmap.FillEllipseCentered(
                    (int)point.X,
                    (int)point.Y,
                    (int)_jointThickness,
                    (int)_jointThickness,
                    joint.TrackingState == TrackingState.Inferred ? inferredJointColor : jointColor);
            }
        }
        private static void DrawBone(IBody body, BitmapContext context, CustomBoneType bone, Color color)
        {
            var startJoint = body.Joints[bone.StartJoint];
            var endJoint = body.Joints[bone.EndJoint];

            // If we can't find either of these joints, exit
            if (startJoint.TrackingState == TrackingState.NotTracked ||
                endJoint.TrackingState == TrackingState.NotTracked)
            {
                return;
            }

            // Don't draw if both points are inferred
            if (startJoint.TrackingState == TrackingState.Inferred &&
                endJoint.TrackingState == TrackingState.Inferred)
            {
                return;
            }

            // If either isn't tracked, it is "inferred"
            if (startJoint.TrackingState != TrackingState.Tracked || endJoint.TrackingState != TrackingState.Tracked)
            {
                color.A = 192;
            }

            var startPoint = GetDepthSpacePoint(startJoint, body.HasMappedDepthPositions);
            var endPoint = GetDepthSpacePoint(endJoint, body.HasMappedDepthPositions);

            context.WriteableBitmap.DrawLineAa(
                (int)startPoint.X,
                (int)startPoint.Y,
                (int)endPoint.X,
                (int)endPoint.Y,
                color);
        }
	public BitmapRenderer(LWF lwf, BitmapContext context) : base(lwf)
	{
		m_context = context;
		m_matrix = new Matrix4x4();
		m_colorMult = new UnityEngine.Color();
		m_colorAdd = new UnityEngine.Color();
		m_available = false;

		if (m_context != null)
			m_context.factory.AddBitmap();
	}
        private static void AAWidthLine(int width, int height, BitmapContext context, float x1, float y1, float x2, float y2, float lineWidth, Int32 color)
        {
            // Perform cohen-sutherland clipping if either point is out of the viewport
            if (!CohenSutherlandLineClip(new Rect(0, 0, width, height), ref x1, ref y1, ref x2, ref y2))
            {
                return;
            }

            if (lineWidth <= 0)
            {
                return;
            }

            var buffer = context.Pixels;

            if (y1 > y2)
            {
                Swap(ref x1, ref x2);
                Swap(ref y1, ref y2);
            }

            if (x1 == x2)
            {
                x1 -= (int)lineWidth / 2;
                x2 += (int)lineWidth / 2;

                if (x1 < 0)
                {
                    x1 = 0;
                }
                if (x2 < 0)
                {
                    return;
                }

                if (x1 >= width)
                {
                    return;
                }
                if (x2 >= width)
                {
                    x2 = width - 1;
                }

                if (y1 >= height || y2 < 0)
                {
                    return;
                }

                if (y1 < 0)
                {
                    y1 = 0;
                }
                if (y2 >= height)
                {
                    y2 = height - 1;
                }

                for (var x = (int)x1; x <= x2; x++)
                {
                    for (var y = (int)y1; y <= y2; y++)
                    {
                        var a = (byte)((color & 0xff000000) >> 24);
                        var r = (byte)((color & 0x00ff0000) >> 16);
                        var g = (byte)((color & 0x0000ff00) >> 8);
                        var b = (byte)((color & 0x000000ff) >> 0);

                        byte rs, gs, bs;
                        byte rd, gd, bd;

                        int d;

                        rs = r;
                        gs = g;
                        bs = b;

                        d = buffer[y * width + x];

                        rd = (byte)((d & 0x00ff0000) >> 16);
                        gd = (byte)((d & 0x0000ff00) >> 8);
                        bd = (byte)((d & 0x000000ff) >> 0);

                        rd = (byte)((rs * a + rd * (0xff - a)) >> 8);
                        gd = (byte)((gs * a + gd * (0xff - a)) >> 8);
                        bd = (byte)((bs * a + bd * (0xff - a)) >> 8);

                        buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0);
                    }
                }

                return;
            }
            if (y1 == y2)
            {
                if (x1 > x2)
                {
                    Swap(ref x1, ref x2);
                }

                y1 -= (int)lineWidth / 2;
                y2 += (int)lineWidth / 2;

                if (y1 < 0)
                {
                    y1 = 0;
                }
                if (y2 < 0)
                {
                    return;
                }

                if (y1 >= height)
                {
                    return;
                }
                if (y2 >= height)
                {
                    x2 = height - 1;
                }

                if (x1 >= width || y2 < 0)
                {
                    return;
                }

                if (x1 < 0)
                {
                    x1 = 0;
                }
                if (x2 >= width)
                {
                    x2 = width - 1;
                }

                for (var x = (int)x1; x <= x2; x++)
                {
                    for (var y = (int)y1; y <= y2; y++)
                    {
                        var a = (byte)((color & 0xff000000) >> 24);
                        var r = (byte)((color & 0x00ff0000) >> 16);
                        var g = (byte)((color & 0x0000ff00) >> 8);
                        var b = (byte)((color & 0x000000ff) >> 0);

                        Byte rs, gs, bs;
                        Byte rd, gd, bd;

                        Int32 d;

                        rs = r;
                        gs = g;
                        bs = b;

                        d = buffer[y * width + x];

                        rd = (byte)((d & 0x00ff0000) >> 16);
                        gd = (byte)((d & 0x0000ff00) >> 8);
                        bd = (byte)((d & 0x000000ff) >> 0);

                        rd = (byte)((rs * a + rd * (0xff - a)) >> 8);
                        gd = (byte)((gs * a + gd * (0xff - a)) >> 8);
                        bd = (byte)((bs * a + bd * (0xff - a)) >> 8);

                        buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0);
                    }
                }

                return;
            }

            y1 += 1;
            y2 += 1;

            var slope  = (y2 - y1) / (x2 - x1);
            var islope = (x2 - x1) / (y2 - y1);

            var m = slope;
            var w = lineWidth;

            var dx = x2 - x1;
            var dy = y2 - y1;

            var xtot = (float)(w * dy / Math.Sqrt(dx * dx + dy * dy));
            var ytot = (float)(w * dx / Math.Sqrt(dx * dx + dy * dy));

            var sm = dx * dy / (dx * dx + dy * dy);

            // Center it.

            x1 += xtot / 2;
            y1 -= ytot / 2;
            x2 += xtot / 2;
            y2 -= ytot / 2;

            //
            //

            var sx = -xtot;
            var sy = +ytot;

            var ix1 = (int)x1;
            var iy1 = (int)y1;

            var ix2 = (int)x2;
            var iy2 = (int)y2;

            var ix3 = (int)(x1 + sx);
            var iy3 = (int)(y1 + sy);

            var ix4 = (int)(x2 + sx);
            var iy4 = (int)(y2 + sy);

            if (lineWidth == 2)
            {
                if (Math.Abs(dy) < Math.Abs(dx))
                {
                    if (x1 < x2)
                    {
                        iy3 = iy1 + 2;
                        iy4 = iy2 + 2;
                    }
                    else
                    {
                        iy1 = iy3 + 2;
                        iy2 = iy4 + 2;
                    }
                }
                else
                {
                    ix1 = ix3 + 2;
                    ix2 = ix4 + 2;
                }
            }

            var starty = Math.Min(Math.Min(iy1, iy2), Math.Min(iy3, iy4));
            var endy   = Math.Max(Math.Max(iy1, iy2), Math.Max(iy3, iy4));

            if (starty < 0)
            {
                starty = -1;
            }
            if (endy >= height)
            {
                endy = height + 1;
            }

            for (var y = starty + 1; y < endy - 1; y++)
            {
                leftEdgeX[y]  = -1 << 16;
                rightEdgeX[y] = 1 << 16 - 1;
            }


            AALineQ1(width, height, context, ix1, iy1, ix2, iy2, color, sy > 0, false);
            AALineQ1(width, height, context, ix3, iy3, ix4, iy4, color, sy < 0, true);

            if (lineWidth > 1)
            {
                AALineQ1(width, height, context, ix1, iy1, ix3, iy3, color, true, sy > 0);
                AALineQ1(width, height, context, ix2, iy2, ix4, iy4, color, false, sy < 0);
            }

            if (x1 < x2)
            {
                if (iy2 >= 0 && iy2 < height)
                {
                    rightEdgeX[iy2] = Math.Min(ix2, rightEdgeX[iy2]);
                }
                if (iy3 >= 0 && iy3 < height)
                {
                    leftEdgeX[iy3] = Math.Max(ix3, leftEdgeX[iy3]);
                }
            }
            else
            {
                if (iy1 >= 0 && iy1 < height)
                {
                    rightEdgeX[iy1] = Math.Min(ix1, rightEdgeX[iy1]);
                }
                if (iy4 >= 0 && iy4 < height)
                {
                    leftEdgeX[iy4] = Math.Max(ix4, leftEdgeX[iy4]);
                }
            }

            //return;

            for (var y = starty + 1; y < endy - 1; y++)
            {
                leftEdgeX[y]  = Math.Max(leftEdgeX[y], 0);
                rightEdgeX[y] = Math.Min(rightEdgeX[y], width - 1);

                for (var x = leftEdgeX[y]; x <= rightEdgeX[y]; x++)
                {
                    var a = (byte)((color & 0xff000000) >> 24);
                    var r = (byte)((color & 0x00ff0000) >> 16);
                    var g = (byte)((color & 0x0000ff00) >> 8);
                    var b = (byte)((color & 0x000000ff) >> 0);

                    Byte rs, gs, bs;
                    Byte rd, gd, bd;

                    Int32 d;

                    rs = r;
                    gs = g;
                    bs = b;

                    d = buffer[y * width + x];

                    rd = (byte)((d & 0x00ff0000) >> 16);
                    gd = (byte)((d & 0x0000ff00) >> 8);
                    bd = (byte)((d & 0x000000ff) >> 0);

                    rd = (byte)((rs * a + rd * (0xff - a)) >> 8);
                    gd = (byte)((gs * a + gd * (0xff - a)) >> 8);
                    bd = (byte)((bs * a + bd * (0xff - a)) >> 8);

                    buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0);
                }
            }
        }
        public static unsafe void Blit(this WriteableBitmap bmp, Rect destRect, WriteableBitmap source, Rect sourceRect, Color color, WriteableBitmapExtensions.BlendMode blendMode)
        {
            if ((int)color.A == 0)
            {
                return;
            }
            bool flag1 = source.Format == PixelFormats.Pbgra32 || source.Format == PixelFormats.Prgba64 || source.Format == PixelFormats.Prgba128Float;
            int  num1  = (int)destRect.Width;
            int  num2  = (int)destRect.Height;

            using (BitmapContext bitmapContext1 = WriteableBitmapContextExtensions.GetBitmapContext(source, ReadWriteMode.ReadOnly))
            {
                using (BitmapContext bitmapContext2 = WriteableBitmapContextExtensions.GetBitmapContext(bmp))
                {
                    int  width1 = bitmapContext1.Width;
                    int  width2 = bitmapContext2.Width;
                    int  height = bitmapContext2.Height;
                    Rect rect   = new Rect(0.0, 0.0, (double)width2, (double)height);
                    rect.Intersect(destRect);
                    if (rect.IsEmpty)
                    {
                        return;
                    }
                    int *  pixels1 = bitmapContext1.Pixels;
                    int *  pixels2 = bitmapContext2.Pixels;
                    int    length  = bitmapContext1.Length;
                    int    num3    = (int)destRect.X;
                    int    num4    = (int)destRect.Y;
                    int    num5    = 0;
                    int    num6    = 0;
                    int    num7    = 0;
                    int    num8    = 0;
                    int    num9    = (int)color.A;
                    int    num10   = (int)color.R;
                    int    num11   = (int)color.G;
                    int    num12   = (int)color.B;
                    bool   flag2   = color != Colors.White;
                    int    num13   = (int)sourceRect.Width;
                    double num14   = sourceRect.Width / destRect.Width;
                    double num15   = sourceRect.Height / destRect.Height;
                    int    num16   = (int)sourceRect.X;
                    int    num17   = (int)sourceRect.Y;
                    int    num18   = -1;
                    int    num19   = -1;
                    double num20   = (double)num17;
                    int    num21   = num4;
                    for (int index1 = 0; index1 < num2; ++index1)
                    {
                        if (num21 >= 0 && num21 < height)
                        {
                            double num22  = (double)num16;
                            int    index2 = num3 + num21 * width2;
                            int    num23  = num3;
                            int    num24  = *pixels1;
                            if (blendMode == WriteableBitmapExtensions.BlendMode.None && !flag2)
                            {
                                int num25 = (int)num22 + (int)num20 * width1;
                                int num26 = num23 < 0 ? -num23 : 0;
                                int num27 = num23 + num26;
                                int num28 = width1 - num26;
                                int num29 = num27 + num28 < width2 ? num28 : width2 - num27;
                                if (num29 > num13)
                                {
                                    num29 = num13;
                                }
                                if (num29 > num1)
                                {
                                    num29 = num1;
                                }
                                BitmapContext.BlockCopy(bitmapContext1, (num25 + num26) * 4, bitmapContext2, (index2 + num26) * 4, num29 * 4);
                            }
                            else
                            {
                                for (int index3 = 0; index3 < num1; ++index3)
                                {
                                    if (num23 >= 0 && num23 < width2)
                                    {
                                        if ((int)num22 != num18 || (int)num20 != num19)
                                        {
                                            int index4 = (int)num22 + (int)num20 * width1;
                                            if (index4 >= 0 && index4 < length)
                                            {
                                                num24 = pixels1[index4];
                                                num8  = num24 >> 24 & (int)Byte.MaxValue;
                                                num5  = num24 >> 16 & (int)Byte.MaxValue;
                                                num6  = num24 >> 8 & (int)Byte.MaxValue;
                                                num7  = num24 & (int)Byte.MaxValue;
                                                if (flag2 && num8 != 0)
                                                {
                                                    num8  = num8 * num9 * 32897 >> 23;
                                                    num5  = (num5 * num10 * 32897 >> 23) * num9 * 32897 >> 23;
                                                    num6  = (num6 * num11 * 32897 >> 23) * num9 * 32897 >> 23;
                                                    num7  = (num7 * num12 * 32897 >> 23) * num9 * 32897 >> 23;
                                                    num24 = num8 << 24 | num5 << 16 | num6 << 8 | num7;
                                                }
                                            }
                                            else
                                            {
                                                num8 = 0;
                                            }
                                        }
                                        if (blendMode == WriteableBitmapExtensions.BlendMode.None)
                                        {
                                            pixels2[index2] = num24;
                                        }
                                        else if (blendMode == WriteableBitmapExtensions.BlendMode.ColorKeying)
                                        {
                                            num5 = num24 >> 16 & (int)Byte.MaxValue;
                                            num6 = num24 >> 8 & (int)Byte.MaxValue;
                                            num7 = num24 & (int)Byte.MaxValue;
                                            if (num5 != (int)color.R || num6 != (int)color.G || num7 != (int)color.B)
                                            {
                                                pixels2[index2] = num24;
                                            }
                                        }
                                        else if (blendMode == WriteableBitmapExtensions.BlendMode.Mask)
                                        {
                                            int num25 = pixels2[index2];
                                            int num26 = num25 >> 24 & (int)Byte.MaxValue;
                                            int num27 = num25 >> 16 & (int)Byte.MaxValue;
                                            int num28 = num25 >> 8 & (int)Byte.MaxValue;
                                            int num29 = num25 & (int)Byte.MaxValue;
                                            int num30 = num26 * num8 * 32897 >> 23 << 24 | num27 * num8 * 32897 >> 23 << 16 | num28 * num8 * 32897 >> 23 << 8 | num29 * num8 * 32897 >> 23;
                                            pixels2[index2] = num30;
                                        }
                                        else if (num8 > 0)
                                        {
                                            int num25 = pixels2[index2];
                                            int num26 = num25 >> 24 & (int)Byte.MaxValue;
                                            if ((num8 == (int)Byte.MaxValue || num26 == 0) && (blendMode != WriteableBitmapExtensions.BlendMode.Additive && blendMode != WriteableBitmapExtensions.BlendMode.Subtractive) && blendMode != WriteableBitmapExtensions.BlendMode.Multiply)
                                            {
                                                pixels2[index2] = num24;
                                            }
                                            else
                                            {
                                                int num27 = num25 >> 16 & (int)Byte.MaxValue;
                                                int num28 = num25 >> 8 & (int)Byte.MaxValue;
                                                int num29 = num25 & (int)Byte.MaxValue;
                                                if (blendMode == WriteableBitmapExtensions.BlendMode.Alpha)
                                                {
                                                    int num30 = (int)Byte.MaxValue - num8;
                                                    num25 = !flag1 ? (num26 & (int)Byte.MaxValue) << 24 | (num5 * num8 + num30 * num27 >> 8 & (int)Byte.MaxValue) << 16 | (num6 * num8 + num30 * num28 >> 8 & (int)Byte.MaxValue) << 8 | num7 * num8 + num30 * num29 >> 8 & (int)Byte.MaxValue : (num26 & (int)Byte.MaxValue) << 24 | ((num5 << 8) + num30 * num27 >> 8 & (int)Byte.MaxValue) << 16 | ((num6 << 8) + num30 * num28 >> 8 & (int)Byte.MaxValue) << 8 | (num7 << 8) + num30 * num29 >> 8 & (int)Byte.MaxValue;
                                                }
                                                else if (blendMode == WriteableBitmapExtensions.BlendMode.Additive)
                                                {
                                                    int num30 = (int)Byte.MaxValue <= num8 + num26 ? (int)Byte.MaxValue : num8 + num26;
                                                    num25 = num30 << 24 | (num30 <= num5 + num27 ? num30 : num5 + num27) << 16 | (num30 <= num6 + num28 ? num30 : num6 + num28) << 8 | (num30 <= num7 + num29 ? num30 : num7 + num29);
                                                }
                                                else if (blendMode == WriteableBitmapExtensions.BlendMode.Subtractive)
                                                {
                                                    num25 = num26 << 24 | (num5 >= num27 ? 0 : num5 - num27) << 16 | (num6 >= num28 ? 0 : num6 - num28) << 8 | (num7 >= num29 ? 0 : num7 - num29);
                                                }
                                                else if (blendMode == WriteableBitmapExtensions.BlendMode.Multiply)
                                                {
                                                    int num30 = num8 * num26 + 128;
                                                    int num31 = num5 * num27 + 128;
                                                    int num32 = num6 * num28 + 128;
                                                    int num33 = num7 * num29 + 128;
                                                    int num34 = (num30 >> 8) + num30 >> 8;
                                                    int num35 = (num31 >> 8) + num31 >> 8;
                                                    int num36 = (num32 >> 8) + num32 >> 8;
                                                    int num37 = (num33 >> 8) + num33 >> 8;
                                                    num25 = num34 << 24 | (num34 <= num35 ? num34 : num35) << 16 | (num34 <= num36 ? num34 : num36) << 8 | (num34 <= num37 ? num34 : num37);
                                                }
                                                pixels2[index2] = num25;
                                            }
                                        }
                                    }
                                    ++num23;
                                    ++index2;
                                    num22 += num14;
                                }
                            }
                        }
                        num20 += num15;
                        ++num21;
                    }
                }
            }
        }
        /// <summary>
        /// Draws a segment of a Cardinal spline (cubic) defined by four control points.
        /// </summary>
        /// <param name="x1">The x-coordinate of the 1st control point.</param>
        /// <param name="y1">The y-coordinate of the 1st control point.</param>
        /// <param name="x2">The x-coordinate of the 2nd control point.</param>
        /// <param name="y2">The y-coordinate of the 2nd control point.</param>
        /// <param name="x3">The x-coordinate of the 3rd control point.</param>
        /// <param name="y3">The y-coordinate of the 3rd control point.</param>
        /// <param name="x4">The x-coordinate of the 4th control point.</param>
        /// <param name="y4">The y-coordinate of the 4th control point.</param>
        /// <param name="tension">The tension of the curve defines the shape. Usually between 0 and 1. 0 would be a straight line.</param>
        /// <param name="color">The color.</param>
        /// <param name="context">The pixel context.</param>
        /// <param name="w">The width of the bitmap.</param>
        /// <param name="h">The height of the bitmap.</param> 
        private static void DrawCurveSegment(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, float tension, int color, BitmapContext context, int w, int h)
        {
            // Determine distances between controls points (bounding rect) to find the optimal stepsize
            var minX = Math.Min(x1, Math.Min(x2, Math.Min(x3, x4)));
            var minY = Math.Min(y1, Math.Min(y2, Math.Min(y3, y4)));
            var maxX = Math.Max(x1, Math.Max(x2, Math.Max(x3, x4)));
            var maxY = Math.Max(y1, Math.Max(y2, Math.Max(y3, y4)));

            // Get slope
            var lenx = maxX - minX;
            var len = maxY - minY;
            if (lenx > len)
            {
                len = lenx;
            }

            // Prevent division by zero
            if (len != 0)
            {
                // Init vars
                var step = StepFactor / len;
                int tx1 = x2;
                int ty1 = y2;
                int tx2, ty2;

                // Calculate factors
                var sx1 = tension * (x3 - x1);
                var sy1 = tension * (y3 - y1);
                var sx2 = tension * (x4 - x2);
                var sy2 = tension * (y4 - y2);
                var ax = sx1 + sx2 + 2 * x2 - 2 * x3;
                var ay = sy1 + sy2 + 2 * y2 - 2 * y3;
                var bx = -2 * sx1 - sx2 - 3 * x2 + 3 * x3;
                var by = -2 * sy1 - sy2 - 3 * y2 + 3 * y3;

                // Interpolate
                for (var t = step; t <= 1; t += step)
                {
                    var tSq = t * t;

                    tx2 = (int)(ax * tSq * t + bx * tSq + sx1 * t + x2);
                    ty2 = (int)(ay * tSq * t + by * tSq + sy1 * t + y2);

                    // Draw line
                    DrawLine(context, w, h, tx1, ty1, tx2, ty2, color);
                    tx1 = tx2;
                    ty1 = ty2;
                }

                // Prevent rounding gap
                DrawLine(context, w, h, tx1, ty1, x3, y3, color);
            }
        }
      /// <summary>
      /// Draws a filled, cubic Beziér spline defined by start, end and two control points.
      /// </summary>
      /// <param name="x1">The x-coordinate of the start point.</param>
      /// <param name="y1">The y-coordinate of the start point.</param>
      /// <param name="cx1">The x-coordinate of the 1st control point.</param>
      /// <param name="cy1">The y-coordinate of the 1st control point.</param>
      /// <param name="cx2">The x-coordinate of the 2nd control point.</param>
      /// <param name="cy2">The y-coordinate of the 2nd control point.</param>
      /// <param name="x2">The x-coordinate of the end point.</param>
      /// <param name="y2">The y-coordinate of the end point.</param>
      /// <param name="color">The color.</param>
      /// <param name="context">The context with the pixels.</param>
      /// <param name="w">The width of the bitmap.</param>
      /// <param name="h">The height of the bitmap.</param> 
      private static List<int> ComputeBezierPoints(int x1, int y1, int cx1, int cy1, int cx2, int cy2, int x2, int y2, int color, BitmapContext context, int w, int h)
      {
         var pixels = context.Pixels;

         // Determine distances between controls points (bounding rect) to find the optimal stepsize
         var minX = Math.Min(x1, Math.Min(cx1, Math.Min(cx2, x2)));
         var minY = Math.Min(y1, Math.Min(cy1, Math.Min(cy2, y2)));
         var maxX = Math.Max(x1, Math.Max(cx1, Math.Max(cx2, x2)));
         var maxY = Math.Max(y1, Math.Max(cy1, Math.Max(cy2, y2)));

         // Get slope
         var lenx = maxX - minX;
         var len = maxY - minY;
         if (lenx > len)
         {
            len = lenx;
         }

         // Prevent divison by zero
         var list = new List<int>();
         if (len != 0)
         {
            // Init vars
            var step = StepFactor / len;
            int tx = x1;
            int ty = y1;

            // Interpolate
            for (var t = 0f; t <= 1; t += step)
            {
               var tSq = t * t;
               var t1 = 1 - t;
               var t1Sq = t1 * t1;

               tx = (int)(t1 * t1Sq * x1 + 3 * t * t1Sq * cx1 + 3 * t1 * tSq * cx2 + t * tSq * x2);
               ty = (int)(t1 * t1Sq * y1 + 3 * t * t1Sq * cy1 + 3 * t1 * tSq * cy2 + t * tSq * y2);

               list.Add(tx);
               list.Add(ty);
            }

            // Prevent rounding gap
            list.Add(x2);
            list.Add(y2);
         }
         return list;
      }
        private static void DrawVertically(BitmapContext context, int x, int y1, int y2, int dotSpace, int dotLength, int color) {
            int width = context.Width;
            int height = context.Height;

            if (x < 0 || x > width) {
                return;
            }

            var pixels = context.Pixels;
            bool on = true;
            int spaceCnt = 0;
            for (int i = y1; i <= y2; i++) {
                if (i < 1) {
                    continue;
                }
                if (i >= height) {
                    break;
                }

                if (on) {
                    //bmp.SetPixel(x, i, color);
                    //var idx = GetIndex(x, i, width);
                    var idx = (i - 1) * width + x - 1;
                    pixels[idx] = color;
                    on = i % dotLength != 0;
                    spaceCnt = 0;
                } else {
                    spaceCnt++;
                    on = spaceCnt % dotSpace == 0;
                }
                //System.Diagnostics.Debug.WriteLine($"{x},{i}, on = {on}");
            }
        }
      /// <summary>
      /// Computes the discrete segment points of a Cardinal spline (cubic) defined by four control points.
      /// </summary>
      /// <param name="x1">The x-coordinate of the 1st control point.</param>
      /// <param name="y1">The y-coordinate of the 1st control point.</param>
      /// <param name="x2">The x-coordinate of the 2nd control point.</param>
      /// <param name="y2">The y-coordinate of the 2nd control point.</param>
      /// <param name="x3">The x-coordinate of the 3rd control point.</param>
      /// <param name="y3">The y-coordinate of the 3rd control point.</param>
      /// <param name="x4">The x-coordinate of the 4th control point.</param>
      /// <param name="y4">The y-coordinate of the 4th control point.</param>
      /// <param name="tension">The tension of the curve defines the shape. Usually between 0 and 1. 0 would be a straight line.</param>
      /// <param name="color">The color.</param>
      /// <param name="context">The context with the pixels.</param>
      /// <param name="w">The width of the bitmap.</param>
      /// <param name="h">The height of the bitmap.</param> 
      private static List<int> ComputeSegmentPoints(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, float tension, int color, BitmapContext context, int w, int h)
      {
         var pixels = context.Pixels;

         // Determine distances between controls points (bounding rect) to find the optimal stepsize
         var minX = Math.Min(x1, Math.Min(x2, Math.Min(x3, x4)));
         var minY = Math.Min(y1, Math.Min(y2, Math.Min(y3, y4)));
         var maxX = Math.Max(x1, Math.Max(x2, Math.Max(x3, x4)));
         var maxY = Math.Max(y1, Math.Max(y2, Math.Max(y3, y4)));

         // Get slope
         var lenx = maxX - minX;
         var len = maxY - minY;
         if (lenx > len)
         {
            len = lenx;
         }

         // Prevent divison by zero
         var list = new List<int>();
         if (len != 0)
         {
            // Init vars
            var step = StepFactor / len;

            // Calculate factors
            var sx1 = tension * (x3 - x1);
            var sy1 = tension * (y3 - y1);
            var sx2 = tension * (x4 - x2);
            var sy2 = tension * (y4 - y2);
            var ax = sx1 + sx2 + 2 * x2 - 2 * x3;
            var ay = sy1 + sy2 + 2 * y2 - 2 * y3;
            var bx = -2 * sx1 - sx2 - 3 * x2 + 3 * x3;
            var by = -2 * sy1 - sy2 - 3 * y2 + 3 * y3;

            // Interpolate
            for (var t = 0f; t <= 1; t += step)
            {
               var tSq = t * t;

               int tx = (int)(ax * tSq * t + bx * tSq + sx1 * t + x2);
               int ty = (int)(ay * tSq * t + by * tSq + sy1 * t + y2);

               list.Add(tx);
               list.Add(ty);
            }

            // Prevent rounding gap
            list.Add(x3);
            list.Add(y3);
         }
         return list;
      }
        private static void Draw(BitmapContext context, int x1, int y1, int x2, int y2, int dotSpace, int dotLength, int color) {
            // y = m * x + n
            // y - m * x = n
            
            int width = context.Width;
            int height = context.Height;

            // Perform cohen-sutherland clipping if either point is out of the viewport
            if (!CohenSutherlandLineClip(new Rect(0, 0, width, height), ref x1, ref y1, ref x2, ref y2)) {
                return;
            }
            Swap(ref x1, ref x2, ref y1, ref y2);
            float m = (y2 - y1) / (float)(x2 - x1);
            float n = y1 - m * x1;
            var pixels = context.Pixels;

            bool on = true;
            int spaceCnt = 0;
            for (int i = x1; i <= width; i++) {
                if (i == 0) {
                    continue;
                }
                int y = (int)(m * i + n);
                if (y <= 0) {
                    continue;
                }
                if (y >= height || i >= x2) {
                    continue;
                }
                if (on) {
                    //bmp.SetPixel(i, y, color);
                    //var idx = GetIndex(i, y, width);
                    var idx = (y - 1) * width + i - 1;
                    pixels[idx] = color;
                    spaceCnt = 0;
                    on = i % dotLength != 0;
                } else {
                    spaceCnt++;
                    on = spaceCnt % dotSpace == 0;
                }
            }
        }
        /// <summary>
        /// Draws a segment of a Cardinal spline (cubic) defined by four control points.
        /// </summary>
        /// <param name="x1">The x-coordinate of the 1st control point.</param>
        /// <param name="y1">The y-coordinate of the 1st control point.</param>
        /// <param name="x2">The x-coordinate of the 2nd control point.</param>
        /// <param name="y2">The y-coordinate of the 2nd control point.</param>
        /// <param name="x3">The x-coordinate of the 3rd control point.</param>
        /// <param name="y3">The y-coordinate of the 3rd control point.</param>
        /// <param name="x4">The x-coordinate of the 4th control point.</param>
        /// <param name="y4">The y-coordinate of the 4th control point.</param>
        /// <param name="tension">The tension of the curve defines the shape. Usually between 0 and 1. 0 would be a straight line.</param>
        /// <param name="color">The color.</param>
        /// <param name="context">The pixel context.</param>
        /// <param name="w">The width of the bitmap.</param>
        /// <param name="h">The height of the bitmap.</param>
        private static void DrawCurveSegment(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, float tension, int color, BitmapContext context, int w, int h)
        {
            // Determine distances between controls points (bounding rect) to find the optimal stepsize
            var minX = Math.Min(x1, Math.Min(x2, Math.Min(x3, x4)));
            var minY = Math.Min(y1, Math.Min(y2, Math.Min(y3, y4)));
            var maxX = Math.Max(x1, Math.Max(x2, Math.Max(x3, x4)));
            var maxY = Math.Max(y1, Math.Max(y2, Math.Max(y3, y4)));

            // Get slope
            var lenx = maxX - minX;
            var len  = maxY - minY;

            if (lenx > len)
            {
                len = lenx;
            }

            // Prevent divison by zero
            if (len != 0)
            {
                // Init vars
                var step = StepFactor / len;
                int tx1 = x2;
                int ty1 = y2;
                int tx2, ty2;

                // Calculate factors
                var sx1 = tension * (x3 - x1);
                var sy1 = tension * (y3 - y1);
                var sx2 = tension * (x4 - x2);
                var sy2 = tension * (y4 - y2);
                var ax  = sx1 + sx2 + (2 * x2) - (2 * x3);
                var ay  = sy1 + sy2 + (2 * y2) - (2 * y3);
                var bx  = (-2 * sx1) - sx2 - (3 * x2) + (3 * x3);
                var by  = (-2 * sy1) - sy2 - (3 * y2) + (3 * y3);

                // Interpolate
                for (var t = step; t <= 1; t += step)
                {
                    var tSq = t * t;

                    tx2 = (int)((ax * tSq * t) + (bx * tSq) + (sx1 * t) + x2);
                    ty2 = (int)((ay * tSq * t) + (by * tSq) + (sy1 * t) + y2);

                    // Draw line
                    DrawLine(context, w, h, tx1, ty1, tx2, ty2, color);
                    tx1 = tx2;
                    ty1 = ty2;
                }

                // Prevent rounding gap
                DrawLine(context, w, h, tx1, ty1, x3, y3, color);
            }
        }
        public static void Blit(BitmapContext destContext, int dpw, int dph, Rect destRect, BitmapContext srcContext, Rect sourceRect, int sourceWidth)
        {
            const BlendMode blendMode = BlendMode.Alpha;

            int dw = (int)destRect.Width;
            int dh = (int)destRect.Height;

            Rect intersect = new Rect(0, 0, dpw, dph);
            intersect.Intersect(destRect);
            if (intersect.IsEmpty)
            {
                return;
            }
#if WPF
            var isPrgba = srcContext.Format == PixelFormats.Pbgra32 || srcContext.Format == PixelFormats.Prgba64 || srcContext.Format == PixelFormats.Prgba128Float;
#endif

            var sourcePixels = srcContext.Pixels;
            var destPixels = destContext.Pixels;
            int sourceLength = srcContext.Length;
            int sourceIdx = -1;
            int px = (int)destRect.X;
            int py = (int)destRect.Y;
            int x;
            int y;
            int idx;
            double ii;
            double jj;
            int sr = 0;
            int sg = 0;
            int sb = 0;
            int dr, dg, db;
            int sourcePixel;
            int sa = 0;
            int da;

            var sw = (int)sourceRect.Width;
            var sdx = sourceRect.Width / destRect.Width;
            var sdy = sourceRect.Height / destRect.Height;
            int sourceStartX = (int)sourceRect.X;
            int sourceStartY = (int)sourceRect.Y;
            int lastii, lastjj;
            lastii = -1;
            lastjj = -1;
            jj = sourceStartY;
            y = py;
            for (var j = 0; j < dh; j++)
            {
                if (y >= 0 && y < dph)
                {
                    ii = sourceStartX;
                    idx = px + y * dpw;
                    x = px;
                    sourcePixel = sourcePixels[0];

                    // Pixel by pixel copying
                    for (var i = 0; i < dw; i++)
                    {
                        if (x >= 0 && x < dpw)
                        {
                            if ((int)ii != lastii || (int)jj != lastjj)
                            {
                                sourceIdx = (int)ii + (int)jj * sourceWidth;
                                if (sourceIdx >= 0 && sourceIdx < sourceLength)
                                {
                                    sourcePixel = sourcePixels[sourceIdx];
                                    sa = ((sourcePixel >> 24) & 0xff);
                                    sr = ((sourcePixel >> 16) & 0xff);
                                    sg = ((sourcePixel >> 8) & 0xff);
                                    sb = ((sourcePixel) & 0xff);
                                }
                                else
                                {
                                    sa = 0;
                                }
                            }

                            if (sa > 0)
                            {
                                int destPixel = destPixels[idx];
                                da = ((destPixel >> 24) & 0xff);
                                if ((sa == 255 || da == 0))
                                {
                                    destPixels[idx] = sourcePixel;
                                }
                                else
                                {
                                    dr = ((destPixel >> 16) & 0xff);
                                    dg = ((destPixel >> 8) & 0xff);
                                    db = ((destPixel) & 0xff);
                                    var isa = 255 - sa;
#if NETFX_CORE
                                    // Special case for WinRT since it does not use pARGB (pre-multiplied alpha)
                                    destPixel = ((da & 0xff) << 24) |
                                                ((((sr * sa + isa * dr) >> 8) & 0xff) << 16) |
                                                ((((sg * sa + isa * dg) >> 8) & 0xff) <<  8) |
                                                (((sb * sa + isa * db) >> 8) & 0xff);
#elif WPF
                                    if (isPrgba)
                                    {
                                        destPixel = ((da & 0xff) << 24) |
                                                    (((((sr << 8) + isa * dr) >> 8) & 0xff) << 16) |
                                                    (((((sg << 8) + isa * dg) >> 8) & 0xff) << 8) |
                                                     ((((sb << 8) + isa * db) >> 8) & 0xff);
                                    }
                                    else
                                    {
                                        destPixel = ((da & 0xff) << 24) |
                                                    (((((sr * sa) + isa * dr) >> 8) & 0xff) << 16) |
                                                    (((((sg * sa) + isa * dg) >> 8) & 0xff) << 8) |
                                                     ((((sb * sa) + isa * db) >> 8) & 0xff);
                                    }
#else
                                    destPixel = ((da & 0xff) << 24) |
                                                (((((sr << 8) + isa * dr) >> 8) & 0xff) << 16) |
                                                (((((sg << 8) + isa * dg) >> 8) & 0xff) << 8) |
                                                 ((((sb << 8) + isa * db) >> 8) & 0xff);
#endif
                                    destPixels[idx] = destPixel;
                                }
                            }
                        }
                        x++;
                        idx++;
                        ii += sdx;
                    }
                }
                jj += sdy;
                y++;
            }

        }
Beispiel #27
0
        /// <summary>
        /// Copies (blits) the pixels from the WriteableBitmap source to the destination WriteableBitmap (this).
        /// </summary>
        /// <param name="bmp">The destination WriteableBitmap.</param>
        /// <param name="destRect">The rectangle that defines the destination region.</param>
        /// <param name="source">The source WriteableBitmap.</param>
        /// <param name="sourceRect">The rectangle that will be copied from the source to the destination.</param>
        /// <param name="color">If not Colors.White, will tint the source image. A partially transparent color and the image will be drawn partially transparent. If the BlendMode is ColorKeying, this color will be used as color key to mask all pixels with this value out.</param>
        /// <param name="blendMode">The blending mode <see cref="BlendMode"/>.</param>
        internal static void Blit(this WriteableBitmap bmp, Rect destRect, WriteableBitmap source, Rect sourceRect, Color color, BlendMode blendMode)
        {
            if (color.A == 0)
            {
                return;
            }
#if WPF
            var isPrgba = source.Format == PixelFormats.Pbgra32 || source.Format == PixelFormats.Prgba64 || source.Format == PixelFormats.Prgba128Float;
#endif
            var dw = (int)destRect.Width;
            var dh = (int)destRect.Height;

            using (var srcContext = source.GetBitmapContext(ReadWriteMode.ReadOnly))
            {
                using (var destContext = bmp.GetBitmapContext())
                {
                    var sourceWidth = srcContext.Width;
                    var dpw         = destContext.Width;
                    var dph         = destContext.Height;

                    var intersect = new Rect(0, 0, dpw, dph);
                    intersect.Intersect(destRect);
                    if (intersect.IsEmpty)
                    {
                        return;
                    }

                    var sourcePixels = srcContext.Pixels;
                    var destPixels   = destContext.Pixels;
                    var sourceLength = srcContext.Length;

                    int sourceIdx = -1;
                    int px        = (int)destRect.X;
                    int py        = (int)destRect.Y;

                    int    x;
                    int    y;
                    int    idx;
                    double ii;
                    double jj;
                    int    sr = 0;
                    int    sg = 0;
                    int    sb = 0;
                    int    dr, dg, db;
                    int    sourcePixel;
                    int    sa = 0;
                    int    da;
                    int    ca = color.A;
                    int    cr = color.R;
                    int    cg = color.G;
                    int    cb = color.B;
                    bool   tinted = color != Colors.White;
                    var    sw = (int)sourceRect.Width;
                    var    sdx = sourceRect.Width / destRect.Width;
                    var    sdy = sourceRect.Height / destRect.Height;
                    int    sourceStartX = (int)sourceRect.X;
                    int    sourceStartY = (int)sourceRect.Y;
                    int    lastii, lastjj;
                    lastii = -1;
                    lastjj = -1;
                    jj     = sourceStartY;
                    y      = py;
                    for (int j = 0; j < dh; j++)
                    {
                        if (y >= 0 && y < dph)
                        {
                            ii          = sourceStartX;
                            idx         = px + (y * dpw);
                            x           = px;
                            sourcePixel = sourcePixels[0];

                            // Scanline BlockCopy is much faster (3.5x) if no tinting and blending is needed,
                            // even for smaller sprites like the 32x32 particles.
                            if (blendMode == BlendMode.None && !tinted)
                            {
                                sourceIdx = (int)ii + ((int)jj * sourceWidth);
                                var offset = x < 0 ? -x : 0;
                                var xx     = x + offset;
                                var wx     = sourceWidth - offset;
                                var len    = xx + wx < dpw ? wx : dpw - xx;
                                if (len > sw)
                                {
                                    len = sw;
                                }

                                if (len > dw)
                                {
                                    len = dw;
                                }

                                BitmapContext.BlockCopy(srcContext, (sourceIdx + offset) * 4, destContext, (idx + offset) * 4, len * 4);
                            }

                            // Pixel by pixel copying
                            else
                            {
                                for (int i = 0; i < dw; i++)
                                {
                                    if (x >= 0 && x < dpw)
                                    {
                                        if ((int)ii != lastii || (int)jj != lastjj)
                                        {
                                            sourceIdx = (int)ii + ((int)jj * sourceWidth);
                                            if (sourceIdx >= 0 && sourceIdx < sourceLength)
                                            {
                                                sourcePixel = sourcePixels[sourceIdx];
                                                sa          = (sourcePixel >> 24) & 0xff;
                                                sr          = (sourcePixel >> 16) & 0xff;
                                                sg          = (sourcePixel >> 8) & 0xff;
                                                sb          = (sourcePixel) & 0xff;
                                                if (tinted && sa != 0)
                                                {
                                                    sa          = (sa * ca * 0x8081) >> 23;
                                                    sr          = (((sr * cr * 0x8081) >> 23) * ca * 0x8081) >> 23;
                                                    sg          = (((sg * cg * 0x8081) >> 23) * ca * 0x8081) >> 23;
                                                    sb          = (((sb * cb * 0x8081) >> 23) * ca * 0x8081) >> 23;
                                                    sourcePixel = (sa << 24) | (sr << 16) | (sg << 8) | sb;
                                                }
                                            }
                                            else
                                            {
                                                sa = 0;
                                            }
                                        }

                                        if (blendMode == BlendMode.None)
                                        {
                                            destPixels[idx] = sourcePixel;
                                        }
                                        else if (blendMode == BlendMode.ColorKeying)
                                        {
                                            sr = (sourcePixel >> 16) & 0xff;
                                            sg = (sourcePixel >> 8) & 0xff;
                                            sb = (sourcePixel) & 0xff;

                                            if (sr != color.R || sg != color.G || sb != color.B)
                                            {
                                                destPixels[idx] = sourcePixel;
                                            }
                                        }
                                        else if (blendMode == BlendMode.Mask)
                                        {
                                            int destPixel = destPixels[idx];
                                            da        = (destPixel >> 24) & 0xff;
                                            dr        = (destPixel >> 16) & 0xff;
                                            dg        = (destPixel >> 8) & 0xff;
                                            db        = (destPixel) & 0xff;
                                            destPixel = (((da * sa * 0x8081) >> 23) << 24) |
                                                        (((dr * sa * 0x8081) >> 23) << 16) |
                                                        (((dg * sa * 0x8081) >> 23) << 8) |
                                                        ((db * sa * 0x8081) >> 23);
                                            destPixels[idx] = destPixel;
                                        }
                                        else if (sa > 0)
                                        {
                                            int destPixel = destPixels[idx];
                                            da = (destPixel >> 24) & 0xff;
                                            if ((sa == 255 || da == 0) &&
                                                blendMode != BlendMode.Additive &&
                                                blendMode != BlendMode.Subtractive &&
                                                blendMode != BlendMode.Multiply)
                                            {
                                                destPixels[idx] = sourcePixel;
                                            }
                                            else
                                            {
                                                dr = (destPixel >> 16) & 0xff;
                                                dg = (destPixel >> 8) & 0xff;
                                                db = (destPixel) & 0xff;
                                                if (blendMode == BlendMode.Alpha)
                                                {
                                                    var isa = 255 - sa;
#if NETFX_CORE
                                                    // Special case for WinRT since it does not use pARGB (pre-multiplied alpha)
                                                    destPixel = ((da & 0xff) << 24) |
                                                                ((((sr * sa + isa * dr) >> 8) & 0xff) << 16) |
                                                                ((((sg * sa + isa * dg) >> 8) & 0xff) << 8) |
                                                                (((sb * sa + isa * db) >> 8) & 0xff);
#elif WPF
                                                    if (isPrgba)
                                                    {
                                                        destPixel = ((da & 0xff) << 24) |
                                                                    (((((sr << 8) + isa * dr) >> 8) & 0xff) << 16) |
                                                                    (((((sg << 8) + isa * dg) >> 8) & 0xff) << 8) |
                                                                    ((((sb << 8) + isa * db) >> 8) & 0xff);
                                                    }
                                                    else
                                                    {
                                                        destPixel = ((da & 0xff) << 24) |
                                                                    (((((sr * sa) + isa * dr) >> 8) & 0xff) << 16) |
                                                                    (((((sg * sa) + isa * dg) >> 8) & 0xff) << 8) |
                                                                    ((((sb * sa) + isa * db) >> 8) & 0xff);
                                                    }
#else
                                                    destPixel = ((da & 0xff) << 24) |
                                                                (((((sr << 8) + (isa * dr)) >> 8) & 0xff) << 16) |
                                                                (((((sg << 8) + (isa * dg)) >> 8) & 0xff) << 8) |
                                                                ((((sb << 8) + (isa * db)) >> 8) & 0xff);
#endif
                                                }
                                                else if (blendMode == BlendMode.Additive)
                                                {
                                                    int a = (255 <= sa + da) ? 255 : (sa + da);
                                                    destPixel = (a << 24) |
                                                                (((a <= sr + dr) ? a : (sr + dr)) << 16) |
                                                                (((a <= sg + dg) ? a : (sg + dg)) << 8) |
                                                                ((a <= sb + db) ? a : (sb + db));
                                                }
                                                else if (blendMode == BlendMode.Subtractive)
                                                {
                                                    int a = da;
                                                    destPixel = (a << 24) |
                                                                (((sr >= dr) ? 0 : (sr - dr)) << 16) |
                                                                (((sg >= dg) ? 0 : (sg - dg)) << 8) |
                                                                ((sb >= db) ? 0 : (sb - db));
                                                }
                                                else if (blendMode == BlendMode.Multiply)
                                                {
                                                    // Faster than a division like (s * d) / 255 are 2 shifts and 2 adds
                                                    int ta = (sa * da) + 128;
                                                    int tr = (sr * dr) + 128;
                                                    int tg = (sg * dg) + 128;
                                                    int tb = (sb * db) + 128;

                                                    int ba = ((ta >> 8) + ta) >> 8;
                                                    int br = ((tr >> 8) + tr) >> 8;
                                                    int bg = ((tg >> 8) + tg) >> 8;
                                                    int bb = ((tb >> 8) + tb) >> 8;

                                                    destPixel = (ba << 24) |
                                                                ((ba <= br ? ba : br) << 16) |
                                                                ((ba <= bg ? ba : bg) << 8) |
                                                                (ba <= bb ? ba : bb);
                                                }

                                                destPixels[idx] = destPixel;
                                            }
                                        }
                                    }

                                    x++;
                                    idx++;
                                    ii += sdx;
                                }
                            }
                        }

                        jj += sdy;
                        y++;
                    }
                }
            }
        }
        /// <summary> 
        /// Blends a specific source color on top of a destination premultiplied color 
        /// </summary> 
        /// <param name="context">Array containing destination color</param> 
        /// <param name="index">Index of destination pixel</param> 
        /// <param name="sa">Source alpha (0..255)</param> 
        /// <param name="srb">Source non-premultiplied red and blue component in the format 0x00rr00bb</param> 
        /// <param name="sg">Source green component (0..255)</param> 
        private static void AlphaBlendNormalOnPremultiplied(BitmapContext context, int index, int sa, uint srb, uint sg)
        {
            var pixels = context.Pixels;
            var destPixel = (uint)pixels[index];

            var da = (destPixel >> 24);
            var dg = ((destPixel >> 8) & 0xff);
            var drb = destPixel & 0x00FF00FF;

            // blend with high-quality alpha and lower quality but faster 1-off RGBs 
            pixels[index] = (int)(
               ((sa + ((da * (255 - sa) * 0x8081) >> 23)) << 24) | // alpha 
               (((sg - dg) * sa + (dg << 8)) & 0xFFFFFF00) | // green 
               (((((srb - drb) * sa) >> 8) + drb) & 0x00FF00FF) // red and blue 
            );
        }
Beispiel #29
0
        public static void Blit(BitmapContext destContext, int dpw, int dph, Rect destRect, BitmapContext srcContext, Rect sourceRect, int sourceWidth)
        {
            const BlendMode blendMode = BlendMode.Alpha;

            int dw = (int)destRect.Width;
            int dh = (int)destRect.Height;

            Rect intersect = new Rect(0, 0, dpw, dph);

            intersect.Intersect(destRect);
            if (intersect.IsEmpty)
            {
                return;
            }
#if WPF
            var isPrgba = srcContext.Format == PixelFormats.Pbgra32 || srcContext.Format == PixelFormats.Prgba64 || srcContext.Format == PixelFormats.Prgba128Float;
#endif

            var    sourcePixels = srcContext.Pixels;
            var    destPixels   = destContext.Pixels;
            int    sourceLength = srcContext.Length;
            int    sourceIdx    = -1;
            int    px           = (int)destRect.X;
            int    py           = (int)destRect.Y;
            int    x;
            int    y;
            int    idx;
            double ii;
            double jj;
            int    sr = 0;
            int    sg = 0;
            int    sb = 0;
            int    dr, dg, db;
            int    sourcePixel;
            int    sa = 0;
            int    da;

            var sw = (int)sourceRect.Width;
            var sdx = sourceRect.Width / destRect.Width;
            var sdy = sourceRect.Height / destRect.Height;
            int sourceStartX = (int)sourceRect.X;
            int sourceStartY = (int)sourceRect.Y;
            int lastii, lastjj;
            lastii = -1;
            lastjj = -1;
            jj     = sourceStartY;
            y      = py;
            for (var j = 0; j < dh; j++)
            {
                if (y >= 0 && y < dph)
                {
                    ii          = sourceStartX;
                    idx         = px + (y * dpw);
                    x           = px;
                    sourcePixel = sourcePixels[0];

                    // Pixel by pixel copying
                    for (var i = 0; i < dw; i++)
                    {
                        if (x >= 0 && x < dpw)
                        {
                            if ((int)ii != lastii || (int)jj != lastjj)
                            {
                                sourceIdx = (int)ii + ((int)jj * sourceWidth);
                                if (sourceIdx >= 0 && sourceIdx < sourceLength)
                                {
                                    sourcePixel = sourcePixels[sourceIdx];
                                    sa          = (sourcePixel >> 24) & 0xff;
                                    sr          = (sourcePixel >> 16) & 0xff;
                                    sg          = (sourcePixel >> 8) & 0xff;
                                    sb          = (sourcePixel) & 0xff;
                                }
                                else
                                {
                                    sa = 0;
                                }
                            }

                            if (sa > 0)
                            {
                                int destPixel = destPixels[idx];
                                da = (destPixel >> 24) & 0xff;
                                if (sa == 255 || da == 0)
                                {
                                    destPixels[idx] = sourcePixel;
                                }
                                else
                                {
                                    dr = (destPixel >> 16) & 0xff;
                                    dg = (destPixel >> 8) & 0xff;
                                    db = (destPixel) & 0xff;
                                    var isa = 255 - sa;
#if NETFX_CORE
                                    // Special case for WinRT since it does not use pARGB (pre-multiplied alpha)
                                    destPixel = ((da & 0xff) << 24) |
                                                ((((sr * sa + isa * dr) >> 8) & 0xff) << 16) |
                                                ((((sg * sa + isa * dg) >> 8) & 0xff) << 8) |
                                                (((sb * sa + isa * db) >> 8) & 0xff);
#elif WPF
                                    if (isPrgba)
                                    {
                                        destPixel = ((da & 0xff) << 24) |
                                                    (((((sr << 8) + isa * dr) >> 8) & 0xff) << 16) |
                                                    (((((sg << 8) + isa * dg) >> 8) & 0xff) << 8) |
                                                    ((((sb << 8) + isa * db) >> 8) & 0xff);
                                    }
                                    else
                                    {
                                        destPixel = ((da & 0xff) << 24) |
                                                    (((((sr * sa) + isa * dr) >> 8) & 0xff) << 16) |
                                                    (((((sg * sa) + isa * dg) >> 8) & 0xff) << 8) |
                                                    ((((sb * sa) + isa * db) >> 8) & 0xff);
                                    }
#else
                                    destPixel = ((da & 0xff) << 24) |
                                                (((((sr << 8) + (isa * dr)) >> 8) & 0xff) << 16) |
                                                (((((sg << 8) + (isa * dg)) >> 8) & 0xff) << 8) |
                                                ((((sb << 8) + (isa * db)) >> 8) & 0xff);
#endif
                                    destPixels[idx] = destPixel;
                                }
                            }
                        }

                        x++;
                        idx++;
                        ii += sdx;
                    }
                }

                jj += sdy;
                y++;
            }
        }
        /// <summary>
        /// Draws a line using a pen / stamp for the line 
        /// </summary>
        /// <param name="context">The context containing the pixels as int RGBA value.</param>
        /// <param name="w">The width of one scanline in the pixels array.</param>
        /// <param name="h">The height of the bitmap.</param>
        /// <param name="x1">The x-coordinate of the start point.</param>
        /// <param name="y1">The y-coordinate of the start point.</param>
        /// <param name="x2">The x-coordinate of the end point.</param>
        /// <param name="y2">The y-coordinate of the end point.</param>
        /// <param name="pen">The pen context.</param>
        public static void DrawLinePenned(BitmapContext context, int w, int h, int x1, int y1, int x2, int y2, BitmapContext pen)
        {
			// Edge case where lines that went out of vertical bounds clipped instead of disappearing
			if((y1 < 0 && y2 < 0) || (y1 > h && y2 > h))
                return;

            if (x1 == x2 && y1 == y2)
                return;

            // Perform cohen-sutherland clipping if either point is out of the viewport
            if (!CohenSutherlandLineClip(new Rect(0, 0, w, h), ref x1, ref y1, ref x2, ref y2)) return;

            int size = pen.WriteableBitmap.PixelWidth;
            int pw = size;
            var srcRect = new Rect(0, 0, size, size);

            // Distance start and end point
            int dx = x2 - x1;
            int dy = y2 - y1;

            // Determine sign for direction x
            int incx = 0;
            if (dx < 0)
            {
                dx = -dx;
                incx = -1;
            }
            else if (dx > 0)
            {
                incx = 1;
            }

            // Determine sign for direction y
            int incy = 0;
            if (dy < 0)
            {
                dy = -dy;
                incy = -1;
            }
            else if (dy > 0)
            {
                incy = 1;
            }

            // Which gradient is larger
            int pdx, pdy, odx, ody, es, el;
            if (dx > dy)
            {
                pdx = incx;
                pdy = 0;
                odx = incx;
                ody = incy;
                es = dy;
                el = dx;
            }
            else
            {
                pdx = 0;
                pdy = incy;
                odx = incx;
                ody = incy;
                es = dx;
                el = dy;
            }

            // Init start
            int x = x1;
            int y = y1;
            int error = el >> 1;

            var destRect = new Rect(x, y, size, size);

            if (y < h && y >= 0 && x < w && x >= 0)
            {
                //Blit(context.WriteableBitmap, new Rect(x,y,3,3), pen.WriteableBitmap, new Rect(0,0,3,3));
                Blit(context, w, h, destRect, pen, srcRect, pw);
                //pixels[y * w + x] = color;
            }

            // Walk the line!
            for (int i = 0; i < el; i++)
            {
                // Update error term
                error -= es;

                // Decide which coord to use
                if (error < 0)
                {
                    error += el;
                    x += odx;
                    y += ody;
                }
                else
                {
                    x += pdx;
                    y += pdy;
                }

                // Set pixel
                if (y < h && y >= 0 && x < w && x >= 0)
                {
                    //Blit(context, w, h, destRect, pen, srcRect, pw);
                    Blit(context, w, h, new Rect(x, y, size, size), pen, srcRect, pw);
                    //Blit(context.WriteableBitmap, destRect, pen.WriteableBitmap, srcRect);
                    //pixels[y * w + x] = color;
                }
            }
        }
 /// <summary>
 /// Creates a new resized bitmap.
 /// </summary>
 /// <param name="srcContext">The source context.</param>
 /// <param name="widthSource">The width of the source pixels.</param>
 /// <param name="heightSource">The height of the source pixels.</param>
 /// <param name="width">The new desired width.</param>
 /// <param name="height">The new desired height.</param>
 /// <param name="interpolation">The interpolation method that should be used.</param>
 /// <returns>A new bitmap that is a resized version of the input.</returns>
 public static int[] Resize(BitmapContext srcContext, int widthSource, int heightSource, int width, int height, Interpolation interpolation)
 {
     return(Resize(srcContext.Pixels, widthSource, heightSource, width, height, interpolation));
 }
 /// <summary> 
 /// Draws an anti-aliased line with a desired stroke thickness
 /// <param name="context">The context containing the pixels as int RGBA value.</param>
 /// <param name="x1">The x-coordinate of the start point.</param>
 /// <param name="y1">The y-coordinate of the start point.</param>
 /// <param name="x2">The x-coordinate of the end point.</param>
 /// <param name="y2">The y-coordinate of the end point.</param>
 /// <param name="color">The color for the line.</param>
 /// <param name="strokeThickness">The stroke thickness of the line.</param>
 /// </summary>
 public static void DrawLineAa(BitmapContext context, int pixelWidth, int pixelHeight, int x1, int y1, int x2, int y2, Color color, int strokeThickness)
 {
     var col = ConvertColor(color);
     AAWidthLine(pixelWidth, pixelHeight, context, x1, y1, x2, y2, strokeThickness, col);
 }
Beispiel #33
0
 /// <summary>
 /// Performs a Copy operation from source Array to destination BitmapContext
 /// </summary>
 /// <remarks>Equivalent to calling Buffer.BlockCopy in Silverlight, or native memcpy in WPF</remarks>
 public static void BlockCopy(Array src, int srcOffset, BitmapContext dest, int destOffset, int count)
 {
     Buffer.BlockCopy(src, srcOffset, dest.Pixels, destOffset, count);
 }
Beispiel #34
0
	public BitmapRenderer(LWF lwf, BitmapContext context) : base(lwf)
	{
		m_context = context;
		m_matrix = new Matrix(0, 0, 0, 0, 0, 0);
		m_matrixForRender = new Matrix4x4();
		m_colorMult = new UnityEngine.Color();
		m_colorAdd = new UnityEngine.Color();
		m_blendMode = (int)Format.Constant.BLEND_MODE_NORMAL;
		m_z = -1;
		m_updated = false;
		m_buffer = null;
		m_bufferIndex = -1;
	}
Beispiel #35
0
            public BitmapRenderer(LWF lwf, BitmapContext context)
                : base(lwf)
            {
                m_context = context;
                m_matrix = new Matrix4x4();
                m_colorMult = new UnityEngine.Color();
                #if LWF_USE_ADDITIONALCOLOR
                m_colorAdd = new UnityEngine.Color();
                #endif

                if (m_context != null)
                m_context.factory.AddBitmap();
            }
 public BitmapRenderer(LWF lwf, BitmapContext context)
     : base(lwf)
 {
     m_context = context;
     m_property = new MaterialPropertyBlock();
     m_matrix = new Matrix4x4();
     m_renderMatrix = new Matrix4x4();
     m_colorMult = new UnityEngine.Color();
     #if LWF_USE_ADDITIONALCOLOR
     m_colorAdd = new UnityEngine.Color();
     #endif
 }
Beispiel #37
0
 public BitmapRenderer(LWF lwf, BitmapContext context)
     : base(lwf)
 {
     m_context = context;
     m_property = new MaterialPropertyBlock();
     m_matrix = new Matrix4x4();
     m_renderMatrix = new Matrix4x4();
     m_colorMult = new UnityEngine.Color();
     m_colorAdd = new UnityEngine.Color();
     m_blendMode = (int)Format.Constant.BLEND_MODE_NORMAL;
     m_colorId = Shader.PropertyToID("_Color");
     m_additionalColorId = Shader.PropertyToID("_AdditionalColor");
 }
 /// <summary>
 /// Creates a new resized bitmap.
 /// </summary>
 /// <param name="srcContext">The source context.</param>
 /// <param name="widthSource">The width of the source pixels.</param>
 /// <param name="heightSource">The height of the source pixels.</param>
 /// <param name="width">The new desired width.</param>
 /// <param name="height">The new desired height.</param>
 /// <param name="interpolation">The interpolation method that should be used.</param>
 /// <returns>A new bitmap that is a resized version of the input.</returns>
 public static int[] Resize(BitmapContext srcContext, int widthSource, int heightSource, int width, int height, Interpolation interpolation)
 {
     return Resize(srcContext.Pixels, widthSource, heightSource, width, height, interpolation);
 }
 /// <summary>
 /// Performs a Copy operation from source BitmapContext to destination Array
 /// </summary>
 /// <remarks>Equivalent to calling Buffer.BlockCopy in Silverlight, or native memcpy in WPF</remarks>
 public static void BlockCopy(BitmapContext src, int srcOffset, byte[] dest, int destOffset, int count)
 {
     Buffer.BlockCopy(src.Pixels, srcOffset, dest, destOffset, count);
 }