diff --git a/Tests/Kernels/GraphicTest/Kernel.cs b/Tests/Kernels/GraphicTest/Kernel.cs
index 8cc1ce5c59..5a37de0f71 100644
--- a/Tests/Kernels/GraphicTest/Kernel.cs
+++ b/Tests/Kernels/GraphicTest/Kernel.cs
@@ -102,6 +102,9 @@ private void DoTest(Canvas aCanvas)
aCanvas.DrawImage(bitmap, 10, 10);
aCanvas.DrawImage(letter, 50, 10);
+ Bitmap GetImageTest = aCanvas.GetImage(50, 10, (int)letter.Width, (int)letter.Height);
+ Assert.AreEqual(GetImageTest.RawData, letter.RawData, "GetImage returns correct values");
+
/* Drawing BitmapHeaderV5 image */
Bitmap v5header = new Bitmap(Convert.FromBase64String(parrot));
aCanvas.DrawImage(v5header,0,0);
diff --git a/source/Cosmos.Core/ManagedMemoryBlock.cs b/source/Cosmos.Core/ManagedMemoryBlock.cs
index 4a6be7d7cf..6daa1aaf42 100644
--- a/source/Cosmos.Core/ManagedMemoryBlock.cs
+++ b/source/Cosmos.Core/ManagedMemoryBlock.cs
@@ -166,6 +166,26 @@ public unsafe void Copy(MemoryBlock block)
MemoryOperations.Copy(xDest, aDataPtr, (int)block.Size);
}
+ ///
+ /// Copies data from the memory block to the specified array.
+ ///
+ /// The start index in the memory block from which to begin copying.
+ /// The array into which data will be copied.
+ /// The starting index in the array where data will be copied.
+ /// The number of elements to copy.
+ public unsafe void Get(int aStart, int[] aData, int aIndex, int aCount)
+ {
+ int* xSrc;
+ fixed (byte* aArrayPtr = memory)
+ {
+ xSrc = (int*)aArrayPtr + aStart;
+ }
+ fixed (int* aDataPtr = aData)
+ {
+ MemoryOperations.Copy(aDataPtr + aIndex, xSrc, aCount);
+ }
+ }
+
///
/// Write 8-bit to the memory block.
///
diff --git a/source/Cosmos.Core/MemoryBlock.cs b/source/Cosmos.Core/MemoryBlock.cs
index bed3816176..2838bd404f 100644
--- a/source/Cosmos.Core/MemoryBlock.cs
+++ b/source/Cosmos.Core/MemoryBlock.cs
@@ -270,6 +270,38 @@ public unsafe void Copy(ManagedMemoryBlock block)
MemoryOperations.Copy(xDest, aDataPtr, (int)block.Size);
}
+ ///
+ /// Copies data from the memory block to the specified array.
+ ///
+ /// The byte offset in the memory block from which to start copying.
+ /// The array into which data will be copied.
+ /// The starting index in the array where data will be copied.
+ /// The number of elements to copy.
+ public unsafe void Get(int aByteOffset, int[] aData, int aIndex, int aCount)
+ {
+ int* xSource = (int*)(Base + aByteOffset);
+ fixed (int* aDataPtr = aData)
+ {
+ MemoryOperations.Copy(aDataPtr + aIndex, xSource, aCount);
+ }
+ }
+
+ ///
+ /// Copies a specified number of bytes from the memory block into an array.
+ ///
+ /// The byte offset in the memory block from where the copy starts.
+ /// The array where the data will be copied to.
+ /// The starting index in the destination array.
+ /// The number of bytes to copy.
+ public unsafe void Get(int aByteOffset, byte[] aData, int aIndex, int aCount)
+ {
+ byte* xSource = (byte*)(Base + aByteOffset);
+ fixed (byte* aDataPtr = aData)
+ {
+ MemoryOperations.Copy(aDataPtr + aIndex, xSource, aCount);
+ }
+ }
+
///
/// Move bytes array down the memory block.
///
diff --git a/source/Cosmos.HAL2/Drivers/Video/VBEDriver.cs b/source/Cosmos.HAL2/Drivers/Video/VBEDriver.cs
index 5182cd263a..015ab5c06b 100644
--- a/source/Cosmos.HAL2/Drivers/Video/VBEDriver.cs
+++ b/source/Cosmos.HAL2/Drivers/Video/VBEDriver.cs
@@ -265,6 +265,18 @@ public uint GetVRAM(uint index)
return (uint)pixel;
}
+ ///
+ /// Get VRAM data.
+ ///
+ /// Start position in VRAM.
+ /// Array to copy data into.
+ /// Starting index in the array to begin copying data.
+ /// Number of elements to copy.
+ public void GetVRAM(int aStart, int[] aData, int aIndex, int aCount)
+ {
+ lastbuffer.Get(aStart, aData, aIndex, aCount);
+ }
+
///
/// Clear VRAM.
///
diff --git a/source/Cosmos.System2/Graphics/Canvas.cs b/source/Cosmos.System2/Graphics/Canvas.cs
index a6ac312140..b464eda8da 100644
--- a/source/Cosmos.System2/Graphics/Canvas.cs
+++ b/source/Cosmos.System2/Graphics/Canvas.cs
@@ -100,6 +100,22 @@ public virtual void Clear(Color color)
/// The Y coordinate.
public abstract void DrawPoint(Color color, int x, int y);
+ ///
+ /// Sets the pixel at the given coordinates to the specified , without unnecessary color operations.
+ ///
+ /// The color to draw with (raw argb).
+ /// The X coordinate.
+ /// The Y coordinate.
+ public abstract void DrawPoint(uint color, int x, int y);
+
+ ///
+ /// Sets the pixel at the given coordinates to the specified . without ToArgb()
+ ///
+ /// The color to draw with (raw argb).
+ /// The X coordinate.
+ /// The Y coordinate.
+ public abstract void DrawPoint(int color, int x, int y);
+
///
/// The name of the Canvas implementation.
///
@@ -117,11 +133,14 @@ public virtual void Clear(Color color)
/// The X coordinate.
/// The Y coordinate.
public abstract Color GetPointColor(int x, int y);
+
///
- /// Gets the index of the pixel at the given coordinates.
+ /// Gets the color of the pixel at the given coordinates in ARGB.
///
/// The X coordinate.
/// The Y coordinate.
+ public abstract int GetRawPointColor(int x, int y);
+
internal int GetPointOffset(int x, int y)
{
return (x * Stride) + (y * Pitch);
@@ -147,6 +166,47 @@ public virtual void DrawArray(Color[] colors, int x, int y, int width, int heigh
}
}
+ ///
+ /// Draws an array of pixels to the canvas, starting at the given coordinates,
+ /// using the given width.
+ ///
+ /// The pixels to draw.
+ /// The X coordinate.
+ /// The Y coordinate.
+ /// The width of the drawn bitmap.
+ /// The height of the drawn bitmap.
+ public virtual void DrawArray(int[] colors, int x, int y, int width, int height)
+ {
+ for (int X = 0; X < width; X++)
+ {
+ for (int Y = 0; Y < height; Y++)
+ {
+ DrawPoint(colors[Y * width + X], x + X, y + Y);
+ }
+ }
+ }
+
+ ///
+ /// Draws an array of pixels to the canvas, starting at the given coordinates,
+ /// using the given width.
+ ///
+ /// The pixels to draw.
+ /// The X coordinate.
+ /// The Y coordinate.
+ /// The width of the drawn bitmap.
+ /// The height of the drawn bitmap.
+ /// int[] colors tarting position
+ public virtual void DrawArray(int[] colors, int x, int y, int width, int height, int startIndex)
+ {
+ for (int X = 0; X < width; X++)
+ {
+ for (int Y = 0; Y < height; Y++)
+ {
+ DrawPoint(colors[Y * width + X + startIndex], x + X, y + Y);
+ }
+ }
+ }
+
///
/// Draws a horizontal line.
///
@@ -317,6 +377,7 @@ public virtual void DrawCircle(Color color, int xCenter, int yCenter, int radius
/// The X center coordinate.
/// The Y center coordinate.
/// The radius of the circle to draw.
+ /// Prevents drawing outside the bounds of the canvas.
public virtual void DrawFilledCircle(Color color, int x0, int y0, int radius)
{
int x = radius;
@@ -485,40 +546,17 @@ public virtual void DrawSquare(Color color, int x, int y, int size)
/// The height of the rectangle.
public virtual void DrawRectangle(Color color, int x, int y, int width, int height)
{
- /*
- * we must draw four lines connecting any vertex of our rectangle to do this we first obtain the position of these
- * vertex (we call these vertexes A, B, C, D as for geometric convention)
- */
-
- /* The check of the validity of x and y are done in DrawLine() */
-
- /* The vertex A is where x,y are */
- int xa = x;
- int ya = y;
-
- /* The vertex B has the same y coordinate of A but x is moved of width pixels */
- int xb = x + width;
- int yb = y;
+ // Draw top edge from (x, y) to (x + width, y)
+ DrawLine(color, x, y, x + width, y);
- /* The vertex C has the same x coordiate of A but this time is y that is moved of height pixels */
- int xc = x;
- int yc = y + height;
+ // Draw left edge from (x, y) to (x, y + height)
+ DrawLine(color, x, y, x, y + height);
- /* The Vertex D has x moved of width pixels and y moved of height pixels */
- int xd = x + width;
- int yd = y + height;
+ // Draw bottom edge from (x, y + height) to (x + width, y + height)
+ DrawLine(color, x, y + height, x + width, y + height);
- /* Draw a line betwen A and B */
- DrawLine(color, xa, ya, xb, yb);
-
- /* Draw a line between A and C */
- DrawLine(color, xa, ya, xc, yc);
-
- /* Draw a line between B and D */
- DrawLine(color, xb, yb, xd, yd);
-
- /* Draw a line between C and D */
- DrawLine(color, xc, yc, xd, yd);
+ // Draw right edge from (x + width, y) to (x + width, y + height)
+ DrawLine(color, x + width, y, x + width, y + height);
}
///
@@ -569,6 +607,7 @@ public virtual void DrawTriangle(Color color, int v1x, int v1y, int v2x, int v2y
/// The image to draw.
/// The origin X coordinate.
/// The origin Y coordinate.
+ /// Prevents drawing outside the bounds of the canvas.
public virtual void DrawImage(Image image, int x, int y, bool preventOffBoundPixels = true)
{
Color color;
@@ -598,6 +637,35 @@ public virtual void DrawImage(Image image, int x, int y, bool preventOffBoundPix
}
}
+ ///
+ /// Creates a bitmap by copying a portion of your canvas from the specified coordinates and dimensions.
+ ///
+ /// The starting X coordinate of the region to copy.
+ /// The starting Y coordinate of the region to copy.
+ /// The width of the region to copy.
+ /// The height of the region to copy.
+ /// A new containing the copied region.
+ public virtual Bitmap GetImage(int x, int y, int width, int height)
+ {
+ Bitmap bitmap = new Bitmap((uint)x, (uint)y, ColorDepth.ColorDepth32);
+
+ for (int posy = y, desty = 0; posy < y + y; posy++, desty++)
+ {
+ for (int posx = x, destx = 0; posx < x + x; posx++, destx++)
+ {
+ bitmap.RawData[desty * x + destx] = GetRawPointColor(posx, posy);
+ }
+ }
+ return bitmap;
+ }
+
+ ///
+ /// Scales an image to the specified new width and height.
+ ///
+ /// The image to be scaled.
+ /// The width of the scaled image.
+ /// The height of the scaled image.
+ /// An array of integers representing the scaled image's pixel data. (Raw bitmap data)
static int[] ScaleImage(Image image, int newWidth, int newHeight)
{
int[] pixels = image.RawData;
@@ -607,7 +675,6 @@ static int[] ScaleImage(Image image, int newWidth, int newHeight)
int xRatio = (int)((w1 << 16) / newWidth) + 1;
int yRatio = (int)((h1 << 16) / newHeight) + 1;
int x2, y2;
-
for (int i = 0; i < newHeight; i++)
{
for (int j = 0; j < newWidth; j++)
@@ -617,7 +684,6 @@ static int[] ScaleImage(Image image, int newWidth, int newHeight)
temp[(i * newWidth) + j] = pixels[(y2 * w1) + x2];
}
}
-
return temp;
}
@@ -629,6 +695,7 @@ static int[] ScaleImage(Image image, int newWidth, int newHeight)
/// The Y coordinate.
/// The desired width to scale the image to before drawing.
/// The desired height to scale the image to before drawing
+ /// Prevents drawing outside the bounds of the canvas.
public virtual void DrawImage(Image image, int x, int y, int w, int h, bool preventOffBoundPixels = true)
{
Color color;
@@ -660,12 +727,39 @@ public virtual void DrawImage(Image image, int x, int y, int w, int h, bool prev
}
}
+ ///
+ /// Draws the given image at the specified coordinates, cropping the image to fit within the maximum width and height.
+ ///
+ /// The image to draw.
+ /// The X coordinate where the image will be drawn.
+ /// The Y coordinate where the image will be drawn.
+ /// The maximum width to display the image. If the image exceeds this width, it will be cropped.
+ /// The maximum height to display the image. If the image exceeds this height, it will be cropped.
+ /// Prevents drawing outside the bounds of the canvas.
+ public virtual void CroppedDrawImage(Image image, int x, int y, int maxWidth, int maxHeight, bool preventOffBoundPixels = true)
+ {
+ Color color;
+ int width = Math.Min((int)image.Width, maxWidth);
+ int height = Math.Min((int)image.Height, maxHeight);
+ int[] pixels = image.RawData;
+
+ for (int xi = 0; xi < width; xi++)
+ {
+ for (int yi = 0; yi < height; yi++)
+ {
+ color = Color.FromArgb(pixels[xi + (yi * image.Width)]);
+ DrawPoint(color, x + xi, y + yi);
+ }
+ }
+ }
+
///
/// Draws an image with alpha blending.
///
/// The image to draw.
/// The X coordinate.
/// The Y coordinate.
+ /// Prevents drawing outside the bounds of the canvas.
public void DrawImageAlpha(Image image, int x, int y, bool preventOffBoundPixels = true)
{
Color color;
diff --git a/source/Cosmos.System2/Graphics/FullScreenCanvas.cs b/source/Cosmos.System2/Graphics/FullScreenCanvas.cs
index 1733e970d2..ca6d5fb417 100644
--- a/source/Cosmos.System2/Graphics/FullScreenCanvas.cs
+++ b/source/Cosmos.System2/Graphics/FullScreenCanvas.cs
@@ -35,7 +35,7 @@ private enum VideoDriver
VGADriver
}
- static Canvas videoDriver = null;
+ private static Canvas videoDriver = null;
static readonly PCIDevice svgaIIDevice = PCI.GetDevice(VendorID.VMWare, DeviceID.SVGAIIAdapter);
///
diff --git a/source/Cosmos.System2/Graphics/SVGAIICanvas.cs b/source/Cosmos.System2/Graphics/SVGAIICanvas.cs
index 32a01de9fe..d0e1488d90 100644
--- a/source/Cosmos.System2/Graphics/SVGAIICanvas.cs
+++ b/source/Cosmos.System2/Graphics/SVGAIICanvas.cs
@@ -17,7 +17,7 @@ public class SVGAIICanvas : Canvas
internal Debugger debugger = new("SVGAIIScreen");
static readonly Mode defaultMode = new(1024, 768, ColorDepth.ColorDepth32);
- private Mode mode;
+ Mode mode;
private readonly VMWareSVGAII driver;
///
@@ -80,23 +80,106 @@ public override void DrawPoint(Color color, int x, int y)
driver.SetPixel((uint)x, (uint)y, (uint)color.ToArgb());
}
+ public override void DrawPoint(uint color, int x, int y)
+ {
+ driver.SetPixel((uint)x, (uint)y, color);
+ }
+
+ public override void DrawPoint(int color, int x, int y)
+ {
+ driver.SetPixel((uint)x, (uint)y, (uint)color);
+ }
+
+ public override void DrawArray(Color[] colors, int x, int y, int width, int height)
+ {
+ ThrowIfCoordNotValid(x, y);
+ ThrowIfCoordNotValid(x + width, y + height);
+
+ for (int i = 0; i < x; i++)
+ {
+ for (int ii = 0; ii < y; ii++)
+ {
+ DrawPoint(colors[i + (ii * width)], i, ii);
+ }
+ }
+ }
+
+ public override void DrawArray(int[] colors, int x, int y, int width, int height)
+ {
+ var frameSize = (int)driver.FrameSize;
+
+ for (int i = 0; i < height; i++)
+ {
+ driver.videoMemory.Copy(GetPointOffset(x, y + i) + frameSize, colors, i * width, width);
+ }
+ }
+
+ public override void DrawArray(int[] colors, int x, int y, int width, int height, int startIndex)
+ {
+ var frameSize = (int)driver.FrameSize;
+
+ for (int i = 0; i < height; i++)
+ {
+ driver.videoMemory.Copy(GetPointOffset(x, y + i) + frameSize, colors, i * width + startIndex, width);
+ }
+ }
+
public override void DrawFilledRectangle(Color color, int xStart, int yStart, int width, int height, bool preventOffBoundPixels = true)
{
var argb = color.ToArgb();
var frameSize = (int)driver.FrameSize;
- if(preventOffBoundPixels)
+ if (preventOffBoundPixels)
{
width = Math.Min(width, (int)mode.Width - xStart);
height = Math.Min(height, (int)mode.Height - yStart);
}
-
-
for (int i = yStart; i < yStart + height; i++)
{
driver.videoMemory.Fill(GetPointOffset(xStart, i) + (int)frameSize, width, argb);
}
}
+ public override void DrawRectangle(Color color, int x, int y, int width, int height)
+ {
+ if (color.A < 255)
+ {
+ // Draw top edge from (x, y) to (x + width, y)
+ DrawLine(color, x, y, x + width, y);
+ // Draw left edge from (x, y) to (x, y + height)
+ DrawLine(color, x, y, x, y + height);
+ // Draw bottom edge from (x, y + height) to (x + width, y + height)
+ DrawLine(color, x, y + height, x + width, y + height);
+ // Draw right edge from (x + width, y) to (x + width, y + height)
+ DrawLine(color, x + width, y, x + width, y + height);
+ }
+ else
+ {
+ int rawColor = color.ToArgb();
+ // Draw top edge from (x, y) to (x + width, y)
+ for (int posX = x; posX < x + width; posX++)
+ {
+ DrawPoint((uint)rawColor, posX, y);
+ }
+ // Draw left edge from (x, y) to (x, y + height)
+ int newY = y + height;
+ for (int posX = x; posX < x + width; posX++)
+ {
+ DrawPoint((uint)rawColor, posX, newY);
+ }
+ // Draw bottom edge from (x, y + height) to (x + width, y + height)
+ for (int posY = y; posY < y + height; posY++)
+ {
+ DrawPoint((uint)rawColor, x, posY);
+ }
+ // Draw right edge from (x + width, y) to (x + width, y + height)
+ int newX = x + width;
+ for (int posY = y; posY < y + height; posY++)
+ {
+ DrawPoint((uint)rawColor, newX, posY);
+ }
+ }
+ }
+
//public override IReadOnlyList AvailableModes { get; } = new List
///
/// Available SVGA 2 supported video modes.
@@ -315,6 +398,27 @@ public override Color GetPointColor(int x, int y)
return Color.FromArgb((int)driver.GetPixel((uint)x, (uint)y));
}
+ public override int GetRawPointColor(int x, int y)
+ {
+ return (int)driver.GetPixel((uint)x, (uint)y);
+ }
+
+ public override Bitmap GetImage(int x, int y, int width, int height)
+ {
+ var frameSize = (int)driver.FrameSize;
+ int[] buffer = new int[width];
+ int[] all = new int[width * height];
+ for (int i = 0; i < height; i++)
+ {
+ driver.videoMemory.Get(GetPointOffset(x, y + i) + frameSize, buffer, 0, width);
+ buffer.CopyTo(all, width * i);
+ }
+ Bitmap toReturn = new Bitmap((uint)width, (uint)height, ColorDepth.ColorDepth32);
+ toReturn.RawData = all;
+
+ return toReturn;
+ }
+
public override void Display()
{
driver.DoubleBufferUpdate();
@@ -357,14 +461,61 @@ public override void DrawImage(Image image, int x, int y, bool preventOffBoundPi
var height = (int)image.Height;
var frameSize = (int)driver.FrameSize;
var data = image.RawData;
+
if (preventOffBoundPixels)
{
var maxWidth = Math.Min(width, (int)mode.Width - x);
var maxHeight = Math.Min(height, (int)mode.Height - y);
+ var startX = Math.Max(0, x);
+ var startY = Math.Max(0, y);
+
+ var sourceX = Math.Max(0, -x);
+ var sourceY = Math.Max(0, -y);
+
+ // Adjust maxWidth and maxHeight if startX or startY were changed
+ maxWidth -= startX - x;
+ maxHeight -= startY - y;
for (int i = 0; i < maxHeight; i++)
{
- driver.videoMemory.Copy(GetPointOffset(x, y + i) + frameSize, data, i * width, maxWidth);
+ int sourceIndex = (sourceY + i) * width + sourceX;
+ driver.videoMemory.Copy(GetPointOffset(startX, startY + i) + frameSize, data, sourceIndex, maxWidth);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < height; i++)
+ {
+ driver.videoMemory.Copy(GetPointOffset(x, y + i) + frameSize, data, i * width, width);
+ }
+ }
+ }
+
+ public override void CroppedDrawImage(Image image, int x, int y, int width, int height, bool preventOffBoundPixels = true)
+ {
+ var frameSize = (int)driver.FrameSize;
+ var data = image.RawData;
+
+ if (preventOffBoundPixels)
+ {
+ var modeWidth = (int)mode.Width;
+ var modeHeight = (int)mode.Height;
+
+ var maxWidth = Math.Min(width, modeWidth - x);
+ var maxHeight = Math.Min(height, modeHeight - y);
+
+ var startX = Math.Max(0, -x);
+ var startY = Math.Max(0, -y);
+
+ var sourceWidth = maxWidth - startX;
+ var sourceHeight = maxHeight - startY;
+
+ for (int i = 0; i < sourceHeight; i++)
+ {
+ int destY = y + startY + i;
+ int destOffset = GetPointOffset(x + startX, destY) + frameSize;
+
+ driver.videoMemory.Copy(destOffset, data, (startY + i) * width + startX, sourceWidth);
}
}
else
diff --git a/source/Cosmos.System2/Graphics/VBECanvas.cs b/source/Cosmos.System2/Graphics/VBECanvas.cs
index bb86dbf1be..493732cbf4 100644
--- a/source/Cosmos.System2/Graphics/VBECanvas.cs
+++ b/source/Cosmos.System2/Graphics/VBECanvas.cs
@@ -14,7 +14,7 @@ namespace Cosmos.System.Graphics
public class VBECanvas : Canvas
{
static readonly Mode defaultMode = new(1024, 768, ColorDepth.ColorDepth32);
- readonly VBEDriver driver;
+ private readonly VBEDriver driver;
Mode mode;
///
@@ -234,6 +234,39 @@ public override void DrawPoint(Color aColor, int aX, int aY)
}
}
+ public override void DrawPoint(uint aColor, int aX, int aY)
+ {
+ uint offset;
+
+ switch (Mode.ColorDepth)
+ {
+ case ColorDepth.ColorDepth32:
+ offset = (uint)GetPointOffset(aX, aY);
+
+ driver.SetVRAM(offset, (byte)((aColor >> 16) & 0xFF));
+ driver.SetVRAM(offset + 1, (byte)((aColor >> 8) & 0xFF));
+ driver.SetVRAM(offset + 2, (byte)(aColor & 0xFF));
+ driver.SetVRAM(offset + 3, (byte)((aColor >> 24) & 0xFF));
+
+ break;
+ case ColorDepth.ColorDepth24:
+ offset = (uint)GetPointOffset(aX, aY);
+
+ driver.SetVRAM(offset, (byte)((aColor >> 16) & 0xFF));
+ driver.SetVRAM(offset + 1, (byte)((aColor >> 8) & 0xFF));
+ driver.SetVRAM(offset + 2, (byte)(aColor & 0xFF));
+
+ break;
+ default:
+ throw new NotImplementedException("Drawing pixels with color depth " + (int)Mode.ColorDepth + " is not yet supported.");
+ }
+ }
+
+ public override void DrawPoint(int aColor, int aX, int aY)
+ {
+ DrawPoint((uint)aColor, aX, aY);
+ }
+
public override void DrawArray(Color[] aColors, int aX, int aY, int aWidth, int aHeight)
{
ThrowIfCoordNotValid(aX, aY);
@@ -248,43 +281,159 @@ public override void DrawArray(Color[] aColors, int aX, int aY, int aWidth, int
}
}
+ public override void DrawArray(int[] aColors, int aX, int aY, int aWidth, int aHeight)
+ {
+ for (int i = 0; i < aHeight; i++)
+ {
+ if (i >= mode.Height)
+ {
+ return;
+ }
+ int destinationIndex = (aY + i) * (int)mode.Width + aX;
+ driver.CopyVRAM(destinationIndex, aColors, i * aWidth, aWidth);
+ }
+ }
+
+ public override void DrawArray(int[] aColors, int aX, int aY, int aWidth, int aHeight, int startIndex)
+ {
+ for (int i = 0; i < aHeight; i++)
+ {
+ if (i >= mode.Height)
+ {
+ return;
+ }
+ int destinationIndex = (aY + i) * (int)mode.Width + aX;
+ driver.CopyVRAM(destinationIndex, aColors, i * aWidth + startIndex, aWidth);
+ }
+ }
+
public override void DrawFilledRectangle(Color aColor, int aX, int aY, int aWidth, int aHeight, bool preventOffBoundPixels = true)
{
// ClearVRAM clears one uint at a time. So we clear pixelwise not byte wise. That's why we divide by 32 and not 8.
- if(preventOffBoundPixels)
- aWidth = (int)(Math.Min(aWidth, Mode.Width - aX) * (int)Mode.ColorDepth / 32);
+ if (preventOffBoundPixels)
+ {
+ aWidth = (int)(Math.Min(aWidth, Mode.Width - aX) * (int)Mode.ColorDepth / 32);
+ }
var color = aColor.ToArgb();
-
for (int i = aY; i < aY + aHeight; i++)
{
driver.ClearVRAM(GetPointOffset(aX, i), aWidth, color);
}
}
- public override void DrawImage(Image aImage, int aX, int aY, bool preventOffBoundPixels = true)
+ public override void DrawRectangle(Color color, int x, int y, int width, int height)
{
- var xBitmap = aImage.RawData;
- var xWidth = (int)aImage.Width;
- var xHeight = (int)aImage.Height;
+ if (color.A < 255)
+ {
+ // Draw top edge from (x, y) to (x + width, y)
+ DrawLine(color, x, y, x + width, y);
+ // Draw left edge from (x, y) to (x, y + height)
+ DrawLine(color, x, y, x, y + height);
+ // Draw bottom edge from (x, y + height) to (x + width, y + height)
+ DrawLine(color, x, y + height, x + width, y + height);
+ // Draw right edge from (x + width, y) to (x + width, y + height)
+ DrawLine(color, x + width, y, x + width, y + height);
+ }
+ else
+ {
+ int rawColor = color.ToArgb();
+ // Draw top edge from (x, y) to (x + width, y)
+ for (int posX = x; posX < x + width; posX++)
+ {
+ DrawPoint((uint)rawColor, posX, y);
+ }
+ // Draw left edge from (x, y) to (x, y + height)
+ int newY = y + height;
+ for (int posX = x; posX < x + width; posX++)
+ {
+ DrawPoint((uint)rawColor, posX, newY);
+ }
+ // Draw bottom edge from (x, y + height) to (x + width, y + height)
+ for (int posY = y; posY < y + height; posY++)
+ {
+ DrawPoint((uint)rawColor, x, posY);
+ }
+ // Draw right edge from (x + width, y) to (x + width, y + height)
+ int newX = x + width;
+ for (int posY = y; posY < y + height; posY++)
+ {
+ DrawPoint((uint)rawColor, newX, posY);
+ }
+ }
+ }
+
+ public override void DrawImage(Image image, int x, int y, bool preventOffBoundPixels = true)
+ {
+ var width = (int)image.Width;
+ var height = (int)image.Height;
+ var data = image.RawData;
+
if (preventOffBoundPixels)
{
- var maxWidth = Math.Min(xWidth, (int)mode.Width - aX);
- var maxHeight = Math.Min(xHeight, (int)mode.Height - aY);
- int xOffset = aY * (int)Mode.Width + aX;
+ var maxWidth = Math.Min(width, (int)mode.Width - x);
+ var maxHeight = Math.Min(height, (int)mode.Height - y);
+ var startX = Math.Max(0, x);
+ var startY = Math.Max(0, y);
+
+ var sourceX = Math.Max(0, -x);
+ var sourceY = Math.Max(0, -y);
+
+ // Adjust maxWidth and maxHeight if startX or startY were changed
+ maxWidth -= startX - x;
+ maxHeight -= startY - y;
+
for (int i = 0; i < maxHeight; i++)
{
- driver.CopyVRAM((i * (int)Mode.Width) + xOffset, xBitmap, i * xWidth, maxWidth);
+ int sourceIndex = (sourceY + i) * width + sourceX;
+ int destinationIndex = (startY + i) * (int)mode.Width + startX;
+ driver.CopyVRAM(destinationIndex, data, sourceIndex, maxWidth);
}
}
else
{
- int xOffset = aY * xHeight + aX;
- for (int i = 0; i < Mode.Height; i++)
+ for (int i = 0; i < height; i++)
{
- driver.CopyVRAM((i * (int)Mode.Width) + xOffset, xBitmap, i * xWidth, xWidth);
+ int destinationIndex = (y + i) * (int)mode.Width + x;
+ driver.CopyVRAM(destinationIndex, data, i * width, width);
}
}
+ }
+
+ public override void CroppedDrawImage(Image aImage, int aX, int aY, int aWidth, int aHeight, bool preventOffBoundPixels = true)
+ {
+ var xBitmap = aImage.RawData;
+ var xWidth = aWidth;
+ var xHeight = aHeight;
+
+ if (preventOffBoundPixels)
+ {
+ var maxWidth = Math.Min(xWidth, (int)Mode.Width - aX);
+ var maxHeight = Math.Min(xHeight, (int)Mode.Height - aY);
+
+ var startX = Math.Max(0, aX);
+ var startY = Math.Max(0, aY);
+ var sourceX = Math.Max(0, -aX);
+ var sourceY = Math.Max(0, -aY);
+
+ maxWidth -= startX - aX;
+ maxHeight -= startY - aY;
+
+ for (int i = 0; i < maxHeight; i++)
+ {
+ int sourceIndex = (sourceY + i) * xWidth + sourceX;
+ int destinationIndex = (startY + i) * (int)Mode.Width + startX;
+ driver.CopyVRAM(destinationIndex, xBitmap, sourceIndex, maxWidth);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < xHeight; i++)
+ {
+ int destinationIndex = (aY + i) * (int)Mode.Width + aX;
+ driver.CopyVRAM(destinationIndex, xBitmap, i * xWidth, xWidth);
+ }
+ }
}
#endregion
@@ -302,6 +451,38 @@ public override Color GetPointColor(int aX, int aY)
return Color.FromArgb((int)driver.GetVRAM(offset));
}
+ public override int GetRawPointColor(int aX, int aY)
+ {
+ uint offset = (uint)GetPointOffset(aX, aY);
+ return (int)driver.GetVRAM(offset);
+ }
+
+ public override Bitmap GetImage(int x, int y, int width, int height)
+ {
+ Bitmap bitmap = new((uint)width, (uint)height, ColorDepth.ColorDepth32);
+
+ int startX = Math.Max(0, x);
+ int startY = Math.Max(0, y);
+ int endX = Math.Min(x + width, (int)Mode.Width);
+ int endY = Math.Min(y + height, (int)Mode.Height);
+
+ int offsetX = Math.Max(0, -x);
+ int offsetY = Math.Max(0, -y);
+
+ int[] rawData = new int[width * height];
+
+ for (int posy = startY; posy < endY; posy++)
+ {
+ int srcOffset = posy * (int)Mode.Width + startX;
+ int destOffset = (posy - startY + offsetY) * width + offsetX;
+
+ driver.GetVRAM(srcOffset, rawData, destOffset, endX - startX);
+ }
+
+ bitmap.RawData = rawData;
+ return bitmap;
+ }
+
#endregion
}
diff --git a/source/Cosmos.System2/Graphics/VGACanvas.cs b/source/Cosmos.System2/Graphics/VGACanvas.cs
index 2157e06dee..9cc89fbd40 100644
--- a/source/Cosmos.System2/Graphics/VGACanvas.cs
+++ b/source/Cosmos.System2/Graphics/VGACanvas.cs
@@ -12,7 +12,7 @@ namespace Cosmos.System.Graphics
public class VGACanvas : Canvas
{
bool enabled;
- readonly VGADriver driver;
+ private readonly VGADriver driver;
///
/// Available VGA supported video modes.
@@ -96,16 +96,48 @@ public override void DrawFilledRectangle(Color aColor, int aXStart, int aYStart,
driver.DrawFilledRectangle(aXStart, aYStart, aWidth, aHeight, driver.GetClosestColorInPalette(aColor));
}
+ public override void DrawRectangle(Color color, int x, int y, int width, int height)
+ {
+ int rawColor = color.ToArgb();
+ /* Draw the top edge */
+ for (int posX = x; posX < x + width; posX++)
+ {
+ DrawPoint((uint)rawColor, posX, y);
+ }
+ /* Draw the bottom edge */
+ int newY = y + height;
+ for (int posX = x; posX < x + width; posX++)
+ {
+ DrawPoint((uint)rawColor, posX, newY);
+ }
+ /* Draw the left edge */
+ for (int posY = y; posY < y + height; posY++)
+ {
+ DrawPoint((uint)rawColor, x, posY);
+ }
+ /* Draw the right edge */
+ int newX = x + width;
+ for (int posY = y; posY < y + height; posY++)
+ {
+ DrawPoint((uint)rawColor, newX, posY);
+ }
+ }
+
public override void DrawPoint(Color aColor, int aX, int aY)
{
driver.SetPixel((uint)aX, (uint)aY, aColor);
}
- public void DrawPoint(uint aColor, int aX, int aY)
+ public override void DrawPoint(uint aColor, int aX, int aY)
{
driver.SetPixel((uint)aX, (uint)aY, aColor);
}
+ public override void DrawPoint(int aColor, int aX, int aY)
+ {
+ driver.SetPixel((uint)aX, (uint)aY, (uint)aColor);
+ }
+
public override List AvailableModes => availableModes;
public override Color GetPointColor(int aX, int aY)
@@ -113,6 +145,11 @@ public override Color GetPointColor(int aX, int aY)
return Color.FromArgb((int)driver.GetPixel((uint)aX, (uint)aY));
}
+ public override int GetRawPointColor(int aX, int aY)
+ {
+ return (int)driver.GetPixel((uint)aX, (uint)aY);
+ }
+
public override Mode DefaultGraphicsMode => new Mode(640, 480, ColorDepth.ColorDepth4);
///