//
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
//
namespace ImageSharp.Drawing.Brushes
{
using System;
using System.Numerics;
using Processors;
///
/// Provides an implementation of a pattern brush for painting patterns.
///
///
/// The patterns that are used to create a custom pattern brush are made up of a repeating matrix of flags,
/// where each flag denotes whether to draw the foreground color or the background color.
/// so to create a new bool[,] with your flags
///
/// For example if you wanted to create a diagonal line that repeat every 4 pixels you would use a pattern like so
/// 1000
/// 0100
/// 0010
/// 0001
///
///
/// or you want a horizontal stripe which is 3 pixels apart you would use a pattern like
/// 1
/// 0
/// 0
///
/// Warning when use array initializer across multiple lines the bools look inverted i.e.
/// new bool[,]{
/// {true, false, false},
/// {false,true, false}
/// }
/// would be
/// 10
/// 01
/// 00
///
/// The pixel format.
public class PatternBrush : IBrush
where TColor : struct, IPackedPixel, IEquatable
{
///
/// The pattern.
///
private readonly TColor[][] pattern;
///
/// The stride width.
///
private readonly int stride;
///
/// Initializes a new instance of the class.
///
/// Color of the fore.
/// Color of the back.
/// The pattern.
public PatternBrush(TColor foreColor, TColor backColor, bool[,] pattern)
{
this.stride = pattern.GetLength(1);
// Convert the multidimension array into a jagged one.
int height = pattern.GetLength(0);
this.pattern = new TColor[height][];
for (int x = 0; x < height; x++)
{
this.pattern[x] = new TColor[this.stride];
for (int y = 0; y < this.stride; y++)
{
if (pattern[x, y])
{
this.pattern[x][y] = foreColor;
}
else
{
this.pattern[x][y] = backColor;
}
}
}
}
///
/// Initializes a new instance of the class.
///
/// The brush.
internal PatternBrush(PatternBrush brush)
{
this.pattern = brush.pattern;
this.stride = brush.stride;
}
///
public BrushApplicator CreateApplicator(PixelAccessor sourcePixels, RectangleF region)
{
return new PatternBrushApplicator(this.pattern, this.stride);
}
///
/// The pattern brush applicator.
///
private class PatternBrushApplicator : BrushApplicator
{
///
/// The patter x-length.
///
private readonly int xLength;
///
/// The stride width.
///
private readonly int stride;
///
/// The pattern.
///
private readonly TColor[][] pattern;
///
/// Initializes a new instance of the class.
///
/// The pattern.
/// The stride.
public PatternBrushApplicator(TColor[][] pattern, int stride)
{
this.pattern = pattern;
this.xLength = pattern.Length;
this.stride = stride;
}
///
/// Gets the color for a single pixel.
///
/// The point.
///
/// The color
///
public override TColor GetColor(Vector2 point)
{
int x = (int)point.X % this.xLength;
int y = (int)point.Y % this.stride;
return this.pattern[x][y];
}
///
public override void Dispose()
{
// noop
}
}
}
}