diff --git a/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/Buffers/BufferIndexed2.cs b/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/Buffers/BufferIndexed2.cs
new file mode 100644
index 000000000..b2514d129
--- /dev/null
+++ b/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/Buffers/BufferIndexed2.cs
@@ -0,0 +1,218 @@
+using Meadow.Peripherals.Displays;
+using System;
+using System.Linq;
+
+namespace Meadow.Foundation.Graphics.Buffers
+{
+ ///
+ /// Represents a 2bpp pixel buffer with indexed colors
+ /// Each pixel is represented by 2 bits, allowing for 4 distinct colors
+ ///
+ public class BufferIndexed2 : PixelBufferBase
+ {
+ ///
+ /// Color mode of the buffer
+ ///
+ public override ColorMode ColorMode => ColorMode.Format2bppIndexed;
+
+ ///
+ /// The indexed colors as a 4 element array of Color values
+ ///
+ public readonly Color[] IndexedColors = new Color[4];
+
+ ///
+ /// Create a new BufferIndexed2 object
+ ///
+ /// The width in pixels
+ /// The height in pixels
+ /// The backing buffer
+ public BufferIndexed2(int width, int height, byte[] buffer) : base(width, height, buffer) { }
+
+ ///
+ /// Create a new BufferIndexed2 object
+ ///
+ /// The width in pixels
+ /// The height in pixels
+ public BufferIndexed2(int width, int height) : base(width, height) { }
+
+ ///
+ /// Create a new BufferIndexed2 object
+ ///
+ public BufferIndexed2() : base() { }
+
+ ///
+ /// Fill buffer with a color
+ ///
+ /// The fill color
+ public override void Fill(Color color)
+ {
+ byte colorValue = (byte)GetIndexForColor(color);
+ Buffer[0] = (byte)(colorValue << 2 | colorValue << 4 | colorValue << 6);
+
+ int arrayMidPoint = Buffer.Length / 2;
+ int copyLength;
+
+ for (copyLength = 1; copyLength < arrayMidPoint; copyLength <<= 1)
+ {
+ Array.Copy(Buffer, 0, Buffer, copyLength, copyLength);
+ }
+
+ Array.Copy(Buffer, 0, Buffer, copyLength, Buffer.Length - copyLength);
+ }
+
+ ///
+ /// Fill a rectangular area with a color
+ ///
+ /// X start position in pixels
+ /// Y start position in pixels
+ /// Width in pixels
+ /// Height in pixels
+ /// The fill color
+ public override void Fill(int x, int y, int width, int height, Color color)
+ {
+ if (x < 0 || x + width > Width ||
+ y < 0 || y + height > Height)
+ {
+ throw new ArgumentOutOfRangeException();
+ }
+
+ //TODO optimize
+ var index = GetIndexForColor(color);
+
+ for (int i = 0; i < width; i++)
+ {
+ for (int j = 0; j < height; j++)
+ {
+ SetPixel(x + i, y + j, index);
+ }
+ }
+ }
+
+ ///
+ /// Get the pixel color at a given coordinate
+ ///
+ /// The X pixel position
+ /// The Y pixel position
+ /// The pixel color
+ public override Color GetPixel(int x, int y)
+ {
+ var index = GetColorIndexForPixel(x, y);
+ return IndexedColors[index];
+ }
+
+ ///
+ /// Set the pixel color
+ ///
+ /// X pixel position
+ /// Y pixel position
+ /// The pixel color
+ public override void SetPixel(int x, int y, Color color)
+ {
+ var index = GetIndexForColor(color);
+ SetPixel(x, y, index);
+ }
+
+ ///
+ /// Set the pixel using a color index
+ ///
+ /// X pixel position
+ /// Y pixel position
+ /// The color index (0-3)
+ public void SetPixel(int x, int y, int colorIndex)
+ {
+ int byteIndex = (y * Width + x) >> 2; // divide by 4 to find the byte
+ int pixelOffset = (x & 0x03) << 1; // (x % 4)*2 bits offset
+
+ // Clear current 2 bits
+ Buffer[byteIndex] &= (byte)~(0x03 << pixelOffset);
+ // Set new bits
+ Buffer[byteIndex] |= (byte)((colorIndex & 0x03) << pixelOffset);
+ }
+
+ ///
+ /// Invert the pixel color
+ ///
+ /// x position of pixel
+ /// y position of pixel
+ public override void InvertPixel(int x, int y)
+ {
+ throw new NotImplementedException("InvertPixel not supported for indexed buffers");
+ }
+
+ ///
+ /// Write a buffer into this buffer at a specified location
+ ///
+ /// x origin
+ /// y origin
+ /// buffer to write
+ public override void WriteBuffer(int x, int y, IPixelBuffer buffer)
+ {
+ if (buffer.ColorMode == ColorMode &&
+ x % 4 == 0 &&
+ buffer.Width % 4 == 0)
+ {
+ // We can do a direct block copy row by row
+ int sourceIndex, destinationIndex;
+ int length = buffer.Width / 2;
+
+ for (int i = 0; i < buffer.Height; i++)
+ {
+ sourceIndex = length * i;
+ destinationIndex = (Width * (y + i) + x) >> 2;
+
+ Array.Copy(buffer.Buffer, sourceIndex, Buffer, destinationIndex, length);
+ }
+ }
+ else
+ { // fall back to a slow write
+ base.WriteBuffer(x, y, buffer);
+ }
+ }
+
+ ///
+ /// Get the pixel's color index (0-3) at a given coordinate
+ ///
+ /// The X pixel position
+ /// The Y pixel position
+ /// The 2-bit color index
+ public byte GetColorIndexForPixel(int x, int y)
+ {
+ int byteIndex = (y * Width + x) >> 2;
+ int pixelOffset = (x & 0x03) << 1;
+
+ byte value = (byte)((Buffer[byteIndex] >> pixelOffset) & 0x03);
+ return value;
+ }
+
+ Color GetClosestColor(Color color)
+ {
+ return IndexedColors[GetIndexForColor(color)];
+ }
+
+ int GetIndexForColor(Color color)
+ {
+ if (IndexedColors == null || IndexedColors.All(x => x == null))
+ {
+ throw new NullReferenceException("No indexed colors assigned");
+ }
+
+ int closestIndex = -1;
+ double shortestDistance = double.MaxValue;
+
+ for (int i = 0; i < IndexedColors.Length; i++)
+ {
+ if (IndexedColors[i] != null)
+ {
+ double distance = GetColorDistance(color, IndexedColors[i]);
+ if (distance < shortestDistance)
+ {
+ shortestDistance = distance;
+ closestIndex = i;
+ if (distance == 0) { break; } // perfect match
+ }
+ }
+ }
+ return closestIndex;
+ }
+ }
+}
diff --git a/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/Buffers/BufferIndexed4.cs b/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/Buffers/BufferIndexed4.cs
index ccfd5e26d..2f7a3be53 100644
--- a/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/Buffers/BufferIndexed4.cs
+++ b/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroGraphics/Driver/Buffers/BufferIndexed4.cs
@@ -6,6 +6,7 @@ namespace Meadow.Foundation.Graphics.Buffers
{
///
/// Represents a 4bpp pixel buffer with indexed colors
+ /// Each pixel is represented by 4 bits, allowing for 8 distinct colors
///
public class BufferIndexed4 : PixelBufferBase
{
@@ -60,7 +61,7 @@ public override void Fill(Color color)
}
///
- /// Fill with a color
+ /// Fill a rectangular area with a color
///
/// X start position in pixels
/// Y start position in pixels
@@ -88,15 +89,14 @@ public override void Fill(int x, int y, int width, int height, Color color)
}
///
- /// Get the pixel color
+ /// Get the pixel color at a given coordinate
///
/// The X pixel position
/// The Y pixel position
/// The pixel color
public override Color GetPixel(int x, int y)
- { //comes back as a 4bit value
+ {
var index = GetColorIndexForPixel(x, y);
-
return IndexedColors[index];
}
@@ -113,11 +113,11 @@ public override void SetPixel(int x, int y, Color color)
}
///
- /// Set the pixel to a shade of gray
+ /// Set the pixel using a color index
///
/// X pixel position
/// Y pixel position
- /// The color index
+ /// The color index (0-7)
public void SetPixel(int x, int y, int colorIndex)
{
int index = y * Width / 2 + x / 2;
@@ -133,7 +133,7 @@ public void SetPixel(int x, int y, int colorIndex)
}
///
- /// Invert the pixel
+ /// Invert the pixel color
///
/// x position of pixel
/// y position of pixel
@@ -143,7 +143,7 @@ public override void InvertPixel(int x, int y)
}
///
- /// Write a buffer to specific location to the current buffer
+ /// Write a buffer into this buffer at a specified location
///
/// x origin
/// y origin
@@ -154,14 +154,14 @@ public override void WriteBuffer(int x, int y, IPixelBuffer buffer)
x % 2 == 0 &&
buffer.Width % 2 == 0)
{
- //we have a happy path
+ // We can do a direct block copy row by row
int sourceIndex, destinationIndex;
int length = buffer.Width / 2;
for (int i = 0; i < buffer.Height; i++)
{
sourceIndex = length * i;
- destinationIndex = (Width * (y + i) + x) >> 2; //divide by 2
+ destinationIndex = (Width * (y + i) + x) >> 2;
Array.Copy(buffer.Buffer, sourceIndex, Buffer, destinationIndex, length);
}
@@ -173,11 +173,11 @@ public override void WriteBuffer(int x, int y, IPixelBuffer buffer)
}
///
- /// Get the pixel color index
+ /// Get the pixel's color index (0-7) at a given coordinate
///
/// The X pixel position
/// The Y pixel position
- /// The pixel color as a 4bpp gray value
+ /// The 4-bit color index
public byte GetColorIndexForPixel(int x, int y)
{
int index = y * Width / 2 + x / 2;
@@ -211,15 +211,14 @@ int GetIndexForColor(Color color)
for (int i = 0; i < IndexedColors.Length; i++)
{
- double distance;
if (IndexedColors[i] != null)
{
- distance = GetColorDistance(color, IndexedColors[i]);
+ double distance = GetColorDistance(color, IndexedColors[i]);
if (distance < shortestDistance)
{
shortestDistance = distance;
closestIndex = i;
- if (distance == 0) { break; } //perfect match
+ if (distance == 0) { break; } // perfect match
}
}
}