Click here to Skip to main content
15,896,915 members
Articles / Mobile Apps / Windows Phone 7

Windows Phone: Are you Game? Part 1

Rate me:
Please Sign up or sign in to vote.
4.77/5 (18 votes)
12 Nov 2011CPOL9 min read 46.4K   693   36  
Introduction to XNA game development for Windows Phone - Includes XNAImage, image manipulation for XNA
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

using Harlinn.WindowsPhone.XNA.Engine.Extensions;

namespace Harlinn.WindowsPhone.XNA.Engine.Imaging
{
  public partial class XNAImage
  {
    /// <summary>
    /// Draws a filled rectangle.
    /// x2 has to be greater than x1 and y2 has to be greater than y1.
    /// </summary>
    /// <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 void FillRectangle(int x1, int y1, int x2, int y2, Color color)
    {
      int abgr = color.ToABGR();
      FillRectangle(x1, y1, x2, y2, abgr);
    }

    /// <summary>
    /// Draws a filled rectangle.
    /// x2 has to be greater than x1 and y2 has to be greater than y1.
    /// </summary>
    /// <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 void FillRectangle(int x1, int y1, int x2, int y2, int color)
    {
      // Check boundaries
      if ((x1 < 0 && x2 < 0) || (y1 < 0 && y2 < 0) || (x1 >= width && x2 >= width) || (y1 >= height && y2 >= height))
      {
        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 > width) 
      { 
        x1 = width; 
      }
      if (y1 > height) 
      { 
        y1 = height; 
      }
      if (x2 > width) 
      { 
        x2 = width; 
      }
      if (y2 > height) 
      { 
        y2 = height; 
      }

      // Fill first line
      int startY = y1 * width;
      int startYPlusX1 = startY + x1;
      int endOffset = startY + x2;
      for (var x = startYPlusX1; x < endOffset; x++)
      {
        pixels[x] = color;
      }

      // Copy first line
      int len = (x2 - x1) * 4;
      int srcOffsetBytes = startYPlusX1 * 4;
      int offset2 = y2 * width + x1;
      for (var y = startYPlusX1 + width; y < offset2; y += width)
      {
        Buffer.BlockCopy(pixels, srcOffsetBytes, pixels, y * 4, len);
      }
    }

    /// <summary>
    /// A Fast Bresenham Type Algorithm For Drawing filled ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf 
    /// x2 has to be greater than x1 and y2 has to be greater than y1.
    /// </summary>
    /// <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 for the line.</param>
    public void FillEllipse(int x1, int y1, int x2, int y2, Color color)
    {
      int abgr = color.ToABGR();
      FillEllipse(x1, y1, x2, y2, abgr);
    }

    /// <summary>
    /// A Fast Bresenham Type Algorithm For Drawing filled ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf 
    /// x2 has to be greater than x1 and y2 has to be greater than y1.
    /// </summary>
    /// <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 for the line.</param>
    public void FillEllipse(int x1, int y1, int x2, int y2, int color)
    {
      // Calc center and radius
      int xr = (x2 - x1) >> 1;
      int yr = (y2 - y1) >> 1;
      int xc = x1 + xr;
      int yc = y1 + yr;
      FillEllipseCentered(xc, yc, xr, yr, color);
    }

    /// <summary>
    /// A Fast Bresenham Type Algorithm For Drawing filled ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf 
    /// Uses a different parameter representation than DrawEllipse().
    /// </summary>
    /// <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 void FillEllipseCentered(int xc, int yc, int xr, int yr, Color color)
    {
      int abgr = color.ToABGR();
      FillEllipseCentered(xc, yc, xr, yr, abgr);
    }

    /// <summary>
    /// A Fast Bresenham Type Algorithm For Drawing filled ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf 
    /// Uses a different parameter representation than DrawEllipse().
    /// </summary>
    /// <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 void FillEllipseCentered(int xc, int yc, int xr, int yr, int color)
    {
      // Use refs for faster access (really important!) speeds up a lot!
      int w = width;
      int h = 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;

        // Draw line
        for (int i = lx; i <= rx; i++)
        {
          pixels[i + uh] = color;      // Quadrant II to I (Actually two octants)
          pixels[i + lh] = color;      // Quadrant III to 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;

        // Draw line
        for (int i = lx; i <= rx; i++)
        {
          pixels[i + uh] = color;      // Quadrant II to I (Actually two octants)
          pixels[i + lh] = color;      // Quadrant III to 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;
        }
      }
    }

    /// <summary>
    /// Draws a filled polygon. Add the first point also at the end of the array if the line should be closed.
    /// </summary>
    /// <param name="points">The points of the polygon 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 void FillPolygon(int[] points, Color color)
    {
      int abgr = color.ToABGR();
      FillPolygon(points, abgr);
    }

    /// <summary>
    /// Draws a filled polygon. Add the first point also at the end of the array if the line should be closed.
    /// </summary>
    /// <param name="points">The points of the polygon 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 void FillPolygon(int[] points, int color)
    {
      // Use refs for faster access (really important!) speeds up a lot!
      int w = width;
      int h = height;
      int pn = points.Length;
      int pnh = points.Length >> 1;
      int[] intersectionsX = new int[pnh];

      // Find y min and max (slightly faster than scanning from 0 to height)
      int yMin = h;
      int yMax = 0;
      for (int i = 1; i < pn; i += 2)
      {
        int py = points[i];
        if (py < yMin) yMin = py;
        if (py > yMax) yMax = py;
      }
      if (yMin < 0) yMin = 0;
      if (yMax >= h) yMax = h - 1;


      // Scan line from min to max
      for (int y = yMin; y <= yMax; y++)
      {
        // Initial point x, y
        float vxi = points[0];
        float vyi = points[1];

        // Find all intersections
        // Based on http://alienryderflex.com/polygon_fill/
        int intersectionCount = 0;
        for (int i = 2; i < pn; i += 2)
        {
          // Next point x, y
          float vxj = points[i];
          float vyj = points[i + 1];

          // Is the scanline between the two points
          if (vyi < y && vyj >= y
           || vyj < y && vyi >= y)
          {
            // Compute the intersection of the scanline with the edge (line between two points)
            intersectionsX[intersectionCount++] = (int)(vxi + (y - vyi) / (vyj - vyi) * (vxj - vxi));
          }
          vxi = vxj;
          vyi = vyj;
        }

        // Sort the intersections from left to right using Insertion sort 
        // It's faster than Array.Sort for this small data set
        int t, j;
        for (int i = 1; i < intersectionCount; i++)
        {
          t = intersectionsX[i];
          j = i;
          while (j > 0 && intersectionsX[j - 1] > t)
          {
            intersectionsX[j] = intersectionsX[j - 1];
            j = j - 1;
          }
          intersectionsX[j] = t;
        }

        // Fill the pixels between the intersections
        for (int i = 0; i < intersectionCount - 1; i += 2)
        {
          int x0 = intersectionsX[i];
          int x1 = intersectionsX[i + 1];

          // Check boundary
          if (x1 > 0 && x0 < w)
          {
            if (x0 < 0) x0 = 0;
            if (x1 >= w) x1 = w - 1;

            // Fill the pixels
            for (int x = x0; x <= x1; x++)
            {
              pixels[y * w + x] = color;
            }
          }
        }
      }
    }

    /// <summary>
    /// Draws a filled quad.
    /// </summary>
    /// <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="x4">The x-coordinate of the 4th point.</param>
    /// <param name="y4">The y-coordinate of the 4th point.</param>
    /// <param name="color">The color.</param>
    public void FillQuad(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, Color color)
    {
      int abgr = color.ToABGR();
      FillQuad(x1, y1, x2, y2, x3, y3, x4, y4, abgr);
    }

    /// <summary>
    /// Draws a filled quad.
    /// </summary>
    /// <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="x4">The x-coordinate of the 4th point.</param>
    /// <param name="y4">The y-coordinate of the 4th point.</param>
    /// <param name="color">The color.</param>
    public void FillQuad(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int color)
    {
      FillPolygon(new int[] { x1, y1, x2, y2, x3, y3, x4, y4, x1, y1 }, color);
    }

    /// <summary>
    /// Draws a filled triangle.
    /// </summary>
    /// <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 void FillTriangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color)
    {
      int abgr = color.ToABGR();
      FillTriangle(x1, y1, x2, y2, x3, y3, abgr);
    }

    /// <summary>
    /// Draws a filled triangle.
    /// </summary>
    /// <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 void FillTriangle(int x1, int y1, int x2, int y2, int x3, int y3, int color)
    {
      FillPolygon(new int[] { x1, y1, x2, y2, x3, y3, x1, y1 }, 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="pixels">The pixels array.</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, int[] pixels, int w, int h)
    {
      // Determine distances between controls points (bounding rect) to find the optimal stepsize
      int minX = Math.Min(x1, Math.Min(cx1, Math.Min(cx2, x2)));
      int minY = Math.Min(y1, Math.Min(cy1, Math.Min(cy2, y2)));
      int maxX = Math.Max(x1, Math.Max(cx1, Math.Max(cx2, x2)));
      int maxY = Math.Max(y1, Math.Max(cy1, Math.Max(cy2, y2)));

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

      // Prevent divison by zero
      List<int> 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;
    }

    /// <summary>
    /// Draws a series of filled, cubic Beziér splines each defined by start, end and two control points. 
    /// The ending point of the previous curve is used as starting point for the next. 
    /// Therfore the inital curve needs four points and the subsequent 3 (2 control and 1 end point).
    /// </summary>
    /// <param name="points">The points for the curve in x and y pairs, therefore the array is interpreted as (x1, y1, cx1, cy1, cx2, cy2, x2, y2, cx3, cx4 ..., xn, yn).</param>
    /// <param name="color">The color for the spline.</param>
    public void FillBeziers(int[] points, Color color)
    {
      int abgr = color.ToABGR();
      FillBeziers(points, abgr);
    }

    /// <summary>
    /// Draws a series of filled, cubic Beziér splines each defined by start, end and two control points. 
    /// The ending point of the previous curve is used as starting point for the next. 
    /// Therfore the inital curve needs four points and the subsequent 3 (2 control and 1 end point).
    /// </summary>
    /// <param name="points">The points for the curve in x and y pairs, therefore the array is interpreted as (x1, y1, cx1, cy1, cx2, cy2, x2, y2, cx3, cx4 ..., xn, yn).</param>
    /// <param name="color">The color for the spline.</param>
    public void FillBeziers(int[] points, int color)
    {
      // Use refs for faster access (really important!) speeds up a lot!
      int w = width;
      int h = height;

      // Compute Beziér curve
      int x1 = points[0];
      int y1 = points[1];
      int x2, y2;
      List<int> list = new List<int>();
      for (int i = 2; i + 5 < points.Length; i += 6)
      {
        x2 = points[i + 4];
        y2 = points[i + 5];
        list.AddRange(ComputeBezierPoints(x1, y1, points[i], points[i + 1], points[i + 2], points[i + 3], x2, y2, color, pixels, w, h));
        x1 = x2;
        y1 = y2;
      }

      // Fill
      FillPolygon(list.ToArray(), color);
    }


    /// <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="pixels">The pixels array.</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, int[] pixels, 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
      var list = new System.Collections.Generic.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;
    }

    /// <summary>
    /// Draws a filled Cardinal spline (cubic) defined by a point collection. 
    /// The cardinal spline passes through each point in the collection.
    /// </summary>
    /// <param name="points">The points for the curve in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, x3, y3, x4, y4, x1, x2 ..., xn, yn).</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 for the spline.</param>
    public void FillCurve(int[] points, float tension, Color color)
    {
      int abgr = color.ToABGR();
      FillCurve(points, tension, abgr);
    }

    /// <summary>
    /// Draws a filled Cardinal spline (cubic) defined by a point collection. 
    /// The cardinal spline passes through each point in the collection.
    /// </summary>
    /// <param name="points">The points for the curve in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, x3, y3, x4, y4, x1, x2 ..., xn, yn).</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 for the spline.</param>
    public void FillCurve(int[] points, float tension, int color)
    {
      // Use refs for faster access (really important!) speeds up a lot!
      int w = width;
      int h = height;

      // First segment
      var list = ComputeSegmentPoints(points[0], points[1], points[0], points[1], points[2], points[3], points[4], points[5], tension, color, pixels, w, h);

      // Middle segments
      int i;
      for (i = 2; i < points.Length - 4; i += 2)
      {
        list.AddRange(ComputeSegmentPoints(points[i - 2], points[i - 1], points[i], points[i + 1], points[i + 2], points[i + 3], points[i + 4], points[i + 5], tension, color, pixels, w, h));
      }

      // Last segment
      list.AddRange(ComputeSegmentPoints(points[i - 2], points[i - 1], points[i], points[i + 1], points[i + 2], points[i + 3], points[i + 2], points[i + 3], tension, color, pixels, w, h));

      // Fill
      FillPolygon(list.ToArray(), color);
    }

    /// <summary>
    /// Draws a filled, closed Cardinal spline (cubic) defined by a point collection. 
    /// The cardinal spline passes through each point in the collection.
    /// </summary>
    /// <param name="points">The points for the curve in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, x3, y3, x4, y4, x1, x2 ..., xn, yn).</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 for the spline.</param>
    public void FillCurveClosed(int[] points, float tension, Color color)
    {
      int abgr = color.ToABGR();
      FillCurveClosed(points, tension, abgr);
    }

    /// <summary>
    /// Draws a filled, closed Cardinal spline (cubic) defined by a point collection. 
    /// The cardinal spline passes through each point in the collection.
    /// </summary>
    /// <param name="points">The points for the curve in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, x3, y3, x4, y4, x1, x2 ..., xn, yn).</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 for the spline.</param>
    public void FillCurveClosed(int[] points, float tension, int color)
    {
      // Use refs for faster access (really important!) speeds up a lot!
      int w = width;
      int h = height;
      int pn = points.Length;

      // First segment
      var list = ComputeSegmentPoints(points[pn - 2], points[pn - 1], points[0], points[1], points[2], points[3], points[4], points[5], tension, color, pixels, w, h);

      // Middle segments
      int i;
      for (i = 2; i < pn - 4; i += 2)
      {
        list.AddRange(ComputeSegmentPoints(points[i - 2], points[i - 1], points[i], points[i + 1], points[i + 2], points[i + 3], points[i + 4], points[i + 5], tension, color, pixels, w, h));
      }

      // Last segment
      list.AddRange(ComputeSegmentPoints(points[i - 2], points[i - 1], points[i], points[i + 1], points[i + 2], points[i + 3], points[0], points[1], tension, color, pixels, w, h));

      // Last-to-First segment
      list.AddRange(ComputeSegmentPoints(points[i], points[i + 1], points[i + 2], points[i + 3], points[0], points[1], points[2], points[3], tension, color, pixels, w, h));

      // Fill
      FillPolygon(list.ToArray(), color);
    }


  }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Sea Surveillance AS
Norway Norway
Chief Architect - Sea Surveillance AS.

Specializing in integrated operations and high performance computing solutions.

I’ve been fooling around with computers since the early eighties, I’ve even done work on CP/M and MP/M.

Wrote my first “real” program on a BBC micro model B based on a series in a magazine at that time. It was fun and I got hooked on this thing called programming ...

A few Highlights:

  • High performance application server development
  • Model Driven Architecture and Code generators
  • Real-Time Distributed Solutions
  • C, C++, C#, Java, TSQL, PL/SQL, Delphi, ActionScript, Perl, Rexx
  • Microsoft SQL Server, Oracle RDBMS, IBM DB2, PostGreSQL
  • AMQP, Apache qpid, RabbitMQ, Microsoft Message Queuing, IBM WebSphereMQ, Oracle TuxidoMQ
  • Oracle WebLogic, IBM WebSphere
  • Corba, COM, DCE, WCF
  • AspenTech InfoPlus.21(IP21), OsiSoft PI


More information about what I do for a living can be found at: harlinn.com or LinkedIn

You can contact me at espen@harlinn.no

Comments and Discussions