Пример #1
0
 public void Update(double elapsedSeconds)
 {
     elapsedRemainder += elapsedSeconds;
     while (elapsedRemainder > updateInterval)
     {
         elapsedRemainder -= updateInterval;
         CreateParticle();
         particleColor.H += .1;
         particleColor.H  = particleColor.H % 255;
         for (int i = Particles.Count - 1; i >= 0; i--)
         {
             Particle p = Particles[i];
             p.Update(updateInterval);
             if (p.Color.A == 0)
             {
                 Particles.Remove(p);
             }
         }
     }
     using (TargetBitmap.GetBitmapContext())
     {
         using (ParticleBitmap.GetBitmapContext(ReadWriteMode.ReadOnly))
         {
             for (int i = 0; i < Particles.Count; i++)
             {
                 Particle p = Particles[i];
                 TargetBitmap.Blit(p.Position, ParticleBitmap, sourceRect, p.Color, BitmapBufferExtensions.BlendMode.Additive);
             }
         }
     }
 }
Пример #2
0
        private void Draw(BitmapBuffer writeableBmp)
        {
            if (this.points != null)
            {
                ReloadRandomPoints();
                // Wrap updates in a GetContext call, to prevent invalidation and nested locking/unlocking during this block
                using (writeableBmp.GetBitmapContext())
                {
                    writeableBmp.Clear();
                    DrawPoints(writeableBmp);
                    //DrawBeziers(writeableBmp);
                    //  DrawCardinal(writeableBmp);

                    //if (ChkShowPoints.IsChecked.Value)
                    //{
                    //    DrawPoints();
                    //}
                    //if (RBBezier.IsChecked.Value)
                    //{
                    //    DrawBeziers();
                    //}
                    //else if (RBCardinal.IsChecked.Value)
                    //{
                    //    DrawCardinal();
                    //}
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Draws random shapes.
        /// </summary>
        private void DrawShapes(BitmapBuffer writeableBmp)
        {
            // Wrap updates in a GetContext call, to prevent invalidation and nested locking/unlocking during this block
            using (writeableBmp.GetBitmapContext())
            {
                // Init some size vars
                int w  = writeableBmp.PixelWidth - 2;
                int h  = writeableBmp.PixelHeight - 2;
                int w2 = w >> 1;
                int h2 = h >> 1;

                // Clear
                writeableBmp.Clear();

                // Fill Shapes
                for (int i = 0; i < shapeCount; i++)
                {
                    // Random polygon
                    int[] p = new int[rand.Next(5, 10) * 2];
                    for (int j = 0; j < p.Length; j += 2)
                    {
                        p[j]     = rand.Next(w);
                        p[j + 1] = rand.Next(h);
                    }
                    writeableBmp.FillPolygon(p, GetRandomColor());
                }

                // Invalidates on exit of Using block
            }
        }
Пример #4
0
        /// <summary>
        /// Draws circles that decrease in size to build a flower that is animated
        /// </summary>
        private void DrawEllipsesFlower(BitmapBuffer writeableBmp)
        {
            // Init some size vars
            int w = writeableBmp.PixelWidth - 2;
            int h = writeableBmp.PixelHeight - 2;

            // Wrap updates in a GetContext call, to prevent invalidation and nested locking/unlocking during this block
            using (writeableBmp.GetBitmapContext())
            {
                // Increment frame counter
                if (++frameCounter >= int.MaxValue || frameCounter < 1)
                {
                    frameCounter = 1;
                }
                double s = Math.Sin(frameCounter * 0.01);
                if (s < 0)
                {
                    s *= -1;
                }

                // Clear
                writeableBmp.Clear();

                // Draw center circle
                int xc = w >> 1;
                int yc = h >> 1;
                // Animate base size with sine
                int r0 = (int)((w + h) * 0.07 * s) + 10;

                BitmapBufferEx.ColorInt color_brown = BitmapBufferEx.ColorInt.FromArgb(
                    255, System.Drawing.Color.Brown.R, System.Drawing.Color.Brown.G, System.Drawing.Color.Brown.B);

                writeableBmp.DrawEllipseCentered(xc, yc, r0, r0, color_brown);

                // Draw outer circles
                int dec    = (int)((w + h) * 0.0045f);
                int r      = (int)((w + h) * 0.025f);
                int offset = r0 + r;
                for (int i = 1; i < 6 && r > 1; i++)
                {
                    for (double f = 1; f < 7; f += 0.7)
                    {
                        // Calc postion based on unit circle
                        int xc2 = (int)(Math.Sin(frameCounter * 0.002 * i + f) * offset + xc);
                        int yc2 = (int)(Math.Cos(frameCounter * 0.002 * i + f) * offset + yc);
                        int col = (int)(0xFFFF0000 | (uint)(0x1A * i) << 8 | (uint)(0x20 * f));
                        writeableBmp.DrawEllipseCentered(xc2, yc2, r, r, col);
                    }
                    // Next ring
                    offset += r;
                    r      -= dec;
                    offset += r;
                }

                // Invalidates on exit of using block
            }
        }
Пример #5
0
        public void Draw(BitmapBuffer writeableBmp)
        {
            // Wrap updates in a GetContext call, to prevent invalidation and nested locking/unlocking during this block
            using (writeableBmp.GetBitmapContext())
            {
                writeableBmp.Clear();
                Draw(writeableBmp, this.Root);
#if SILVERLIGHT
                writeableBmp.Invalidate();
#endif
            }
        }
Пример #6
0
        /// <summary>
        /// Draws a triangle.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the 1st point.</param>
        /// <param name="y1">The y-coordinate of the 1st point.</param>
        /// <param name="x2">The x-coordinate of the 2nd point.</param>
        /// <param name="y2">The y-coordinate of the 2nd point.</param>
        /// <param name="x3">The x-coordinate of the 3rd point.</param>
        /// <param name="y3">The y-coordinate of the 3rd point.</param>
        /// <param name="color">The color.</param>
        public static void DrawTriangle(this BitmapBuffer bmp, int x1, int y1, int x2, int y2, int x3, int y3, int color)
        {
            using (BitmapContext context = bmp.GetBitmapContext())
            {
                // Use refs for faster access (really important!) speeds up a lot!
                int w = context.Width;
                int h = context.Height;

                DrawLine(context, w, h, x1, y1, x2, y2, color);
                DrawLine(context, w, h, x2, y2, x3, y3, color);
                DrawLine(context, w, h, x3, y3, x1, y1, color);
            }
        }
Пример #7
0
        /// <summary>
        /// Draws a polyline anti-aliased. Add the first point also at the end of the array if the line should be closed.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="points">The points of the polyline in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, ..., xn, yn).</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawPolyline(this BitmapBuffer bmp, int[] points, int color)
        {
            using (BitmapContext context = bmp.GetBitmapContext())
            {
                // Use refs for faster access (really important!) speeds up a lot!
                int w  = context.Width;
                int h  = context.Height;
                int x1 = points[0];
                int y1 = points[1];

                int len = points.Length;
                for (int i = 2; i < len; i += 2)
                {
                    DrawLine(context, w, h,
                             x1, y1,
                             x1 += points[i], y1 += points[i + 1], //also update x1,y1
                             color);
                }
            }
        }
Пример #8
0
        /// <summary>
        /// Draws a polyline anti-aliased. Add the first point also at the end of the array if the line should be closed.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="points">The points of the polyline in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, ..., xn, yn).</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawPolylineAa(this BitmapBuffer bmp, int[] points, int color)
        {
            using (var context = bmp.GetBitmapContext())
            {
                // Use refs for faster access (really important!) speeds up a lot!
                int w  = context.Width;
                int h  = context.Height;
                int x1 = points[0];
                int y1 = points[1];

                for (int i = 2; i < points.Length; i += 2)
                {
                    int x2 = points[i];
                    int y2 = points[i + 1];

                    DrawLineAa(context, w, h, x1, y1, x2, y2, color);
                    x1 = x2;
                    y1 = y2;
                }
            }
        }
Пример #9
0
        /// <summary>
        /// Draws random ellipses
        /// </summary>
        private void DrawEllipses(BitmapBuffer writeableBmp)
        {
            // Init some size vars
            int w  = writeableBmp.PixelWidth - 2;
            int h  = writeableBmp.PixelHeight - 2;
            int wh = w >> 1;
            int hh = h >> 1;

            // Wrap updates in a GetContext call, to prevent invalidation and nested locking/unlocking during this block
            using (writeableBmp.GetBitmapContext())
            {
                // Clear
                writeableBmp.Clear();

                // Draw Ellipses
                for (int i = 0; i < shapeCount; i++)
                {
                    writeableBmp.DrawEllipse(rand.Next(wh), rand.Next(hh), rand.Next(wh, w), rand.Next(hh, h),
                                             GetRandomColor());
                }

                // Invalidates on exit of using block
            }
        }
Пример #10
0
        /// <summary>
        /// Draws the different types of shapes.
        /// </summary>
        private void DrawStaticShapes(BitmapBuffer writeableBmp)
        {
            // Wrap updates in a GetContext call, to prevent invalidation and nested locking/unlocking during this block
            using (writeableBmp.GetBitmapContext())
            {
                // Init some size vars
                int w    = writeableBmp.PixelWidth - 2;
                int h    = writeableBmp.PixelHeight - 2;
                int w3rd = w / 3;
                int h3rd = h / 3;
                int w6th = w3rd >> 1;
                int h6th = h3rd >> 1;

                // Clear
                writeableBmp.Clear();

                // Draw some points
                for (int i = 0; i < 200; i++)
                {
                    writeableBmp.SetPixel(rand.Next(w3rd), rand.Next(h3rd), GetRandomColor());
                }

                // Draw Standard shapes
                writeableBmp.DrawLine(rand.Next(w3rd, w3rd * 2), rand.Next(h3rd), rand.Next(w3rd, w3rd * 2), rand.Next(h3rd),
                                      GetRandomColor());
                writeableBmp.DrawTriangle(rand.Next(w3rd * 2, w - w6th), rand.Next(h6th), rand.Next(w3rd * 2, w),
                                          rand.Next(h6th, h3rd), rand.Next(w - w6th, w), rand.Next(h3rd),
                                          GetRandomColor());

                writeableBmp.DrawQuad(rand.Next(0, w6th), rand.Next(h3rd, h3rd + h6th), rand.Next(w6th, w3rd),
                                      rand.Next(h3rd, h3rd + h6th), rand.Next(w6th, w3rd),
                                      rand.Next(h3rd + h6th, 2 * h3rd), rand.Next(0, w6th), rand.Next(h3rd + h6th, 2 * h3rd),
                                      GetRandomColor());
                writeableBmp.DrawRectangle(rand.Next(w3rd, w3rd + w6th), rand.Next(h3rd, h3rd + h6th),
                                           rand.Next(w3rd + w6th, w3rd * 2), rand.Next(h3rd + h6th, 2 * h3rd),
                                           GetRandomColor());

                // Random polyline
                int[] p = new int[rand.Next(7, 10) * 2];
                for (int j = 0; j < p.Length; j += 2)
                {
                    p[j]     = rand.Next(w3rd * 2, w);
                    p[j + 1] = rand.Next(h3rd, 2 * h3rd);
                }
                writeableBmp.DrawPolyline(p, GetRandomColor());

                // Random closed polyline
                p = new int[rand.Next(6, 9) * 2];
                for (int j = 0; j < p.Length - 2; j += 2)
                {
                    p[j]     = rand.Next(w3rd);
                    p[j + 1] = rand.Next(2 * h3rd, h);
                }
                p[p.Length - 2] = p[0];
                p[p.Length - 1] = p[1];
                writeableBmp.DrawPolyline(p, GetRandomColor());

                // Ellipses
                writeableBmp.DrawEllipse(rand.Next(w3rd, w3rd + w6th), rand.Next(h3rd * 2, h - h6th),
                                         rand.Next(w3rd + w6th, w3rd * 2), rand.Next(h - h6th, h), GetRandomColor());
                writeableBmp.DrawEllipseCentered(w - w6th, h - h6th, w6th >> 1, h6th >> 1, GetRandomColor());


                // Draw Grid
                writeableBmp.DrawLine(0, h3rd, w, h3rd, Colors.Black);
                writeableBmp.DrawLine(0, 2 * h3rd, w, 2 * h3rd, Colors.Black);
                writeableBmp.DrawLine(w3rd, 0, w3rd, h, Colors.Black);
                writeableBmp.DrawLine(2 * w3rd, 0, 2 * w3rd, h, Colors.Black);

                // Invalidates on exit of using block
            }
        }
Пример #11
0
        /// <summary>
        /// Draws the different types of shapes.
        /// </summary>
        private void DrawStaticShapes(BitmapBuffer writeableBmp)
        {
            // HideShapeCountText();

            // Wrap updates in a GetContext call, to prevent invalidation and nested locking/unlocking during this block
            using (writeableBmp.GetBitmapContext())
            {
                // Init some size vars
                int w   = writeableBmp.PixelWidth;
                int h   = writeableBmp.PixelHeight;
                int w3  = w / 3;
                int h3  = h / 3;
                int w6  = w3 >> 1;
                int h6  = h3 >> 1;
                int w12 = w6 >> 1;
                int h12 = h6 >> 1;

                // Clear
                writeableBmp.Clear();

                // Fill closed concave polygon
                var p = new int[]
                {
                    w12 >> 1, h12,
                    w6, h3 - (h12 >> 1),
                    w3 - (w12 >> 1), h12,
                    w6 + w12, h12,
                    w6, h6 + h12,
                    w12, h12,
                    w12 >> 1, h12,
                };
                writeableBmp.FillPolygonsEvenOdd(new[] { p }, GetRandomColor());

                // Fill closed convex polygon
                p = new int[]
                {
                    w3 + w6, h12 >> 1,
                    w3 + w6 + w12, h12,
                    w3 + w6 + w12, h6 + h12,
                    w3 + w6, h6 + h12 + (h12 >> 1),
                    w3 + w12, h6 + h12,
                    w3 + w12, h12,
                    w3 + w6, h12 >> 1,
                };
                writeableBmp.FillPolygon(p, GetRandomColor());

                // Fill Triangle + Quad
                writeableBmp.FillTriangle(2 * w3 + w6, h12 >> 1, 2 * w3 + w6 + w12, h6 + h12, 2 * w3 + w12, h6 + h12,
                                          GetRandomColor());
                writeableBmp.FillQuad(w6, h3 + (h12 >> 1), w6 + w12, h3 + h6, w6, h3 + h6 + h12 + (h12 >> 1), w12,
                                      h3 + h6, GetRandomColor());

                // Fill Ellipses
                writeableBmp.FillEllipse(rand.Next(w3, w3 + w6), rand.Next(h3, h3 + h6), rand.Next(w3 + w6, 2 * w3),
                                         rand.Next(h3 + h6, 2 * h3), GetRandomColor());
                writeableBmp.FillEllipseCentered(2 * w3 + w6, h3 + h6, w12, h12, GetRandomColor());

                // Fill closed Cardinal Spline curve
                p = new int[]
                {
                    w12 >> 1, 2 * h3 + h12,
                    w6, h - (h12 >> 1),
                    w3 - (w12 >> 1), 2 * h3 + h12,
                    w6 + w12, 2 * h3 + h12,
                    w6, 2 * h3 + (h12 >> 1),
                    w12, 2 * h3 + h12,
                };
                writeableBmp.FillCurveClosed(p, 0.5f, GetRandomColor());

                // Fill closed Beziér curve
                p = new int[]
                {
                    w3 + w12, 2 * h3 + h6 + h12,
                    w3 + w6 + (w12 >> 1), 2 * h3,
                    w3 + w6 + w12 + (w12 >> 1), 2 * h3,
                    w3 + w6 + w12, 2 * h3 + h6 + h12,
                };
                writeableBmp.FillBeziers(p, GetRandomColor());

                // Fill Rectangle
                writeableBmp.FillRectangle(rand.Next(2 * w3, 2 * w3 + w6), rand.Next(2 * h3, 2 * h3 + h6),
                                           rand.Next(2 * w3 + w6, w), rand.Next(2 * h3 + h6, h), GetRandomColor());
                // Fill another rectangle with alpha blending
                writeableBmp.FillRectangle(rand.Next(2 * w3, 2 * w3 + w6), rand.Next(2 * h3, 2 * h3 + h6),
                                           rand.Next(2 * w3 + w6, w), rand.Next(2 * h3 + h6, h), GetRandomColor(), true);

                BitmapBufferEx.ColorInt black = BitmapBufferEx.ColorInt.FromArgb(255, 0, 0, 0);
                // Draw Grid
                writeableBmp.DrawLine(0, h3, w, h3, Colors.Black);
                writeableBmp.DrawLine(0, 2 * h3, w, 2 * h3, Colors.Black);
                writeableBmp.DrawLine(w3, 0, w3, h, Colors.Black);
                writeableBmp.DrawLine(2 * w3, 0, 2 * w3, h, Colors.Black);

                // Invalidates on exit of Using block
            }
        }
Пример #12
0
        private void DrawFillDemo(BitmapBuffer writeableBmp)
        {
            // Wrap updates in a GetContext call, to prevent invalidation and nested locking/unlocking during this block
            using (writeableBmp.GetBitmapContext())
            {
                // Init some size vars
                int w  = writeableBmp.PixelWidth - 2;
                int h  = writeableBmp.PixelHeight - 2;
                int w2 = w >> 1;
                int h2 = h >> 1;
                int w4 = w2 >> 1;
                int h4 = h2 >> 1;
                int w8 = w4 >> 1;
                int h8 = h4 >> 1;

                // Clear
                writeableBmp.Clear();

                // Add circles
                const float startTimeFixed  = 1;
                const float endTimeFixed    = startTimeFixed + timeStep;
                const float startTimeRandom = 3;
                const float endTimeCurve    = 9.7f;
                const int   intervalRandom  = 2;
                const int   maxCircles      = 30;

                // Spread fixed position and color circles
                if (time > startTimeFixed && time < endTimeFixed)
                {
                    unchecked
                    {
                        circles.Add(new Circle {
                            X = w8, Y = h8, Radius = 10f, Velocity = 1, Color = (int)0xFFC88717
                        });
                        circles.Add(new Circle
                        {
                            X = w8, Y = h - h8, Radius = 10f, Velocity = 1, Color = (int)0xFFFB522B
                        });
                        circles.Add(new Circle
                        {
                            X = w - w8, Y = h8, Radius = 10f, Velocity = 1, Color = (int)0xFFDB6126
                        });
                        circles.Add(new Circle
                        {
                            X = w - w8, Y = h - h8, Radius = 10f, Velocity = 1, Color = (int)0xFFFFCE25
                        });
                    }
                }

                // Spread random position and color circles
                if (time > startTimeRandom && (int)time % intervalRandom == 0)
                {
                    unchecked
                    {
                        circles.Add(new Circle
                        {
                            X        = rand.Next(w),
                            Y        = rand.Next(h),
                            Radius   = 1f,
                            Velocity = rand.Next(1, 5),
                            Color    = rand.Next((int)0xFFFF0000, (int)0xFFFFFFFF),
                        });
                    }
                }

                // Render and update circles
                foreach (var circle in circles)
                {
                    var r = (int)circle.Radius;
                    writeableBmp.FillEllipseCentered(circle.X, circle.Y, r, r, circle.Color);
                    circle.Update();
                }

                if (circles.Count > maxCircles)
                {
                    circles.RemoveAt(0);
                }

                // Fill closed Cardinal Spline curve
                if (time < endTimeCurve)
                {
                    var p = new int[]
                    {
                        w4, h2,
                        w2, h2 + h4,
                        w2 + w4, h2,
                        w2, h4,
                    };
                    writeableBmp.FillCurveClosed(p, (float)Math.Sin(time) * 7, Colors.Black);
                }

                // Update time
                time += timeStep;

                // Invalidates on exit of Using block
            }
        }
Пример #13
0
        /// <summary>
        /// A Fast Bresenham Type Algorithm For Drawing Ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf
        /// Uses a different parameter representation than DrawEllipse().
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="xc">The x-coordinate of the ellipses center.</param>
        /// <param name="yc">The y-coordinate of the ellipses center.</param>
        /// <param name="xr">The radius of the ellipse in x-direction.</param>
        /// <param name="yr">The radius of the ellipse in y-direction.</param>
        /// <param name="color">The color for the line.</param>
        public static unsafe void DrawEllipseCentered(this BitmapBuffer bmp, int xc, int yc, int xr, int yr, int color)
        {
            // Use refs for faster access (really important!) speeds up a lot!
            using (BitmapContext context = bmp.GetBitmapContext())
            {
                int *pixels = context.Pixels._inf32Buffer;

                int w = context.Width;
                int h = context.Height;

                // Avoid endless loop
                if (xr < 1 || yr < 1)
                {
                    return;
                }

                // Init vars
                int uh, lh, uy, ly, lx, rx;
                int x         = xr;
                int y         = 0;
                int xrSqTwo   = (xr * xr) << 1;
                int yrSqTwo   = (yr * yr) << 1;
                int xChg      = yr * yr * (1 - (xr << 1));
                int yChg      = xr * xr;
                int err       = 0;
                int xStopping = yrSqTwo * xr;
                int yStopping = 0;

                // Draw first set of points counter clockwise where tangent line slope > -1.
                while (xStopping >= yStopping)
                {
                    // Draw 4 quadrant points at once
                    uy = yc + y;                  // Upper half
                    ly = yc - y;                  // Lower half
                    if (uy < 0)
                    {
                        uy = 0;                  // Clip
                    }
                    if (uy >= h)
                    {
                        uy = h - 1;               // ...
                    }
                    if (ly < 0)
                    {
                        ly = 0;
                    }
                    if (ly >= h)
                    {
                        ly = h - 1;
                    }
                    uh = uy * w;                  // Upper half
                    lh = ly * w;                  // Lower half

                    rx = xc + x;
                    lx = xc - x;
                    if (rx < 0)
                    {
                        rx = 0;                  // Clip
                    }
                    if (rx >= w)
                    {
                        rx = w - 1;               // ...
                    }
                    if (lx < 0)
                    {
                        lx = 0;
                    }
                    if (lx >= w)
                    {
                        lx = w - 1;
                    }
                    pixels[rx + uh] = color;      // Quadrant I (Actually an octant)
                    pixels[lx + uh] = color;      // Quadrant II
                    pixels[lx + lh] = color;      // Quadrant III
                    pixels[rx + lh] = color;      // Quadrant IV

                    y++;
                    yStopping += xrSqTwo;
                    err       += yChg;
                    yChg      += xrSqTwo;
                    if ((xChg + (err << 1)) > 0)
                    {
                        x--;
                        xStopping -= yrSqTwo;
                        err       += xChg;
                        xChg      += yrSqTwo;
                    }
                }

                // ReInit vars
                x  = 0;
                y  = yr;
                uy = yc + y;                  // Upper half
                ly = yc - y;                  // Lower half
                if (uy < 0)
                {
                    uy = 0;                  // Clip
                }
                if (uy >= h)
                {
                    uy = h - 1;               // ...
                }
                if (ly < 0)
                {
                    ly = 0;
                }
                if (ly >= h)
                {
                    ly = h - 1;
                }
                uh        = uy * w;           // Upper half
                lh        = ly * w;           // Lower half
                xChg      = yr * yr;
                yChg      = xr * xr * (1 - (yr << 1));
                err       = 0;
                xStopping = 0;
                yStopping = xrSqTwo * yr;

                // Draw second set of points clockwise where tangent line slope < -1.
                while (xStopping <= yStopping)
                {
                    // Draw 4 quadrant points at once
                    rx = xc + x;
                    lx = xc - x;
                    if (rx < 0)
                    {
                        rx = 0;                  // Clip
                    }
                    if (rx >= w)
                    {
                        rx = w - 1;               // ...
                    }
                    if (lx < 0)
                    {
                        lx = 0;
                    }
                    if (lx >= w)
                    {
                        lx = w - 1;
                    }
                    pixels[rx + uh] = color;      // Quadrant I (Actually an octant)
                    pixels[lx + uh] = color;      // Quadrant II
                    pixels[lx + lh] = color;      // Quadrant III
                    pixels[rx + lh] = color;      // Quadrant IV

                    x++;
                    xStopping += yrSqTwo;
                    err       += xChg;
                    xChg      += yrSqTwo;
                    if ((yChg + (err << 1)) > 0)
                    {
                        y--;
                        uy = yc + y;                  // Upper half
                        ly = yc - y;                  // Lower half
                        if (uy < 0)
                        {
                            uy = 0;                  // Clip
                        }
                        if (uy >= h)
                        {
                            uy = h - 1;               // ...
                        }
                        if (ly < 0)
                        {
                            ly = 0;
                        }
                        if (ly >= h)
                        {
                            ly = h - 1;
                        }
                        uh         = uy * w;          // Upper half
                        lh         = ly * w;          // Lower half
                        yStopping -= xrSqTwo;
                        err       += yChg;
                        yChg      += xrSqTwo;
                    }
                }
            }
        }
Пример #14
0
        /// <summary>
        /// Draws a rectangle.
        /// x2 has to be greater than x1 and y2 has to be greater than y1.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the bounding rectangle's left side.</param>
        /// <param name="y1">The y-coordinate of the bounding rectangle's top side.</param>
        /// <param name="x2">The x-coordinate of the bounding rectangle's right side.</param>
        /// <param name="y2">The y-coordinate of the bounding rectangle's bottom side.</param>
        /// <param name="color">The color.</param>
        public static unsafe void DrawRectangle(this BitmapBuffer bmp, int x1, int y1, int x2, int y2, int color)
        {
            using (BitmapContext context = bmp.GetBitmapContext())
            {
                // Use refs for faster access (really important!) speeds up a lot!
                int  w      = context.Width;
                int  h      = context.Height;
                int *pixels = context.Pixels._inf32Buffer;

                // Check boundaries
                if ((x1 < 0 && x2 < 0) || (y1 < 0 && y2 < 0) ||
                    (x1 >= w && x2 >= w) || (y1 >= h && y2 >= h))
                {
                    return;
                }

                // Clamp boundaries
                if (x1 < 0)
                {
                    x1 = 0;
                }
                if (y1 < 0)
                {
                    y1 = 0;
                }
                if (x2 < 0)
                {
                    x2 = 0;
                }
                if (y2 < 0)
                {
                    y2 = 0;
                }
                if (x1 >= w)
                {
                    x1 = w - 1;
                }
                if (y1 >= h)
                {
                    y1 = h - 1;
                }
                if (x2 >= w)
                {
                    x2 = w - 1;
                }
                if (y2 >= h)
                {
                    y2 = h - 1;
                }

                int startY = y1 * w;
                int endY   = y2 * w;

                int offset2      = endY + x1;
                int endOffset    = startY + x2;
                int startYPlusX1 = startY + x1;

                // top and bottom horizontal scanlines
                for (int x = startYPlusX1; x <= endOffset; x++)
                {
                    pixels[x]       = color; // top horizontal line
                    pixels[offset2] = color; // bottom horizontal line
                    offset2++;
                }

                // offset2 == endY + x2

                // vertical scanlines
                endOffset = startYPlusX1 + w;
                offset2  -= w;

                for (int y = startY + x2 + w; y <= offset2; y += w)
                {
                    pixels[y]         = color; // right vertical line
                    pixels[endOffset] = color; // left vertical line
                    endOffset        += w;
                }
            }
        }
Пример #15
0
        /// <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 BitmapBuffer bmp, BitmapBuffer 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(Affine.IdentityMatrix);
                }

                int[]           destPixels = destContext.Pixels;
                int             destWidth  = destContext.Width;
                int             destHeight = destContext.Height;
                MatrixTransform 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;

                    RectD sourceRect = new RectD(0, 0, sourceWidth, sourceHeight);
                    RectD destRect   = new RectD(0, 0, destWidth, destHeight);
                    RectD 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
                    PointD zeroZero = inverse.Transform(new PointD(startX, startY));
                    PointD oneZero  = inverse.Transform(new PointD(startX + 1, startY));
                    PointD zeroOne  = inverse.Transform(new PointD(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;
                    }
                }
            }
        }
Пример #16
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 BitmapBuffer bmp, RectD destRect, BitmapBuffer source, RectD sourceRect, ColorInt color, BlendMode blendMode)
        {
            if (color.A == 0)
            {
                return;
            }
#if WPF
            bool isPrgba = source.Format == PixelFormats.Pbgra32 || source.Format == PixelFormats.Prgba64 || source.Format == PixelFormats.Prgba128Float;
#endif
            int dw = (int)destRect.Width;
            int dh = (int)destRect.Height;

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

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

                    int[] sourcePixels = srcContext.Pixels;
                    int[] 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;
                    int    ca = color.A;
                    int    cr = color.R;
                    int    cg = color.G;
                    int    cb = color.B;
                    bool   tinted = color != Colors.White;
                    int    sw = (int)sourceRect.Width;
                    double sdx = sourceRect.Width / destRect.Width;
                    double 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;
                                int offset = x < 0 ? -x : 0;
                                int xx     = x + offset;
                                int wx     = sourceWidth - offset;
                                int 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 (!color.EqualsOnRGB(sr, sg, sb))
                                            {
                                                destPixels[idx] = sourcePixel;
                                            }
                                            //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)
                                                {
                                                    int 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++;
                    }
                }
        }