--- /dev/null
+#include "precomp.h"
+
+/* GLOBALS *******************************************************************/
+
+static ULONG ScrollRegion[4] =
+{
+ 0,
+ 0,
+ 640 - 1,
+ 480 - 1
+};
+static UCHAR lMaskTable[8] =
+{
+ (1 << 8) - (1 << 0),
+ (1 << 7) - (1 << 0),
+ (1 << 6) - (1 << 0),
+ (1 << 5) - (1 << 0),
+ (1 << 4) - (1 << 0),
+ (1 << 3) - (1 << 0),
+ (1 << 2) - (1 << 0),
+ (1 << 1) - (1 << 0)
+};
+static UCHAR rMaskTable[8] =
+{
+ (1 << 7),
+ (1 << 7)+ (1 << 6),
+ (1 << 7)+ (1 << 6) + (1 << 5),
+ (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4),
+ (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3),
+ (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3) + (1 << 2),
+ (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3) + (1 << 2) + (1 << 1),
+ (1 << 7)+ (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3) + (1 << 2) + (1 << 1) +
+ (1 << 0),
+};
+UCHAR PixelMask[8] =
+{
+ (1 << 7),
+ (1 << 6),
+ (1 << 5),
+ (1 << 4),
+ (1 << 3),
+ (1 << 2),
+ (1 << 1),
+ (1 << 0),
+};
+static ULONG lookup[16] =
+{
+ 0x0000,
+ 0x0100,
+ 0x1000,
+ 0x1100,
+ 0x0001,
+ 0x0101,
+ 0x1001,
+ 0x1101,
+ 0x0010,
+ 0x0110,
+ 0x1010,
+ 0x1110,
+ 0x0011,
+ 0x0111,
+ 0x1011,
+ 0x1111,
+};
+
+ULONG_PTR VgaRegisterBase = 0;
+ULONG_PTR VgaBase = 0;
+ULONG curr_x = 0;
+ULONG curr_y = 0;
+static ULONG VidTextColor = 0xF;
+static BOOLEAN CarriageReturn = FALSE;
+
+#define __outpb(Port, Value) \
+ WRITE_PORT_UCHAR((PUCHAR)(VgaRegisterBase + (Port)), (UCHAR)(Value))
+
+#define __outpw(Port, Value) \
+ WRITE_PORT_USHORT((PUSHORT)(VgaRegisterBase + (Port)), (USHORT)(Value))
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+static VOID
+NTAPI
+ReadWriteMode(IN UCHAR Mode)
+{
+ UCHAR Value;
+
+ /* Switch to graphics mode register */
+ __outpb(0x3CE, 5);
+
+ /* Get the current register value, minus the current mode */
+ Value = READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF) & 0xF4;
+
+ /* Set the new mode */
+ __outpb(0x3CF, Mode | Value);
+}
+
+FORCEINLINE
+VOID
+SetPixel(IN ULONG Left,
+ IN ULONG Top,
+ IN UCHAR Color)
+{
+ PUCHAR PixelPosition;
+
+ /* Calculate the pixel position. */
+ PixelPosition = (PUCHAR)(VgaBase + (Left >> 3) + (Top * 80));
+
+ /* Select the bitmask register and write the mask */
+ __outpw(0x3CE, (PixelMask[Left & 7] << 8) | 8);
+
+ /* Read the current pixel value and add our color */
+ WRITE_REGISTER_UCHAR(PixelPosition,
+ READ_REGISTER_UCHAR(PixelPosition) & Color);
+}
+
+#define SET_PIXELS(_PixelPtr, _PixelMask, _TextColor) \
+do { \
+ /* Select the bitmask register and write the mask */ \
+ __outpw(0x3CE, ((_PixelMask) << 8) | 8); \
+ /* Set the new color */ \
+ WRITE_REGISTER_UCHAR((_PixelPtr), (UCHAR)(_TextColor)); \
+} while (0);
+
+#ifdef CHAR_GEN_UPSIDE_DOWN
+# define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT] + BOOTCHAR_HEIGHT - 1;
+# define FONT_PTR_DELTA (-1)
+#else
+# define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT];
+# define FONT_PTR_DELTA (1)
+#endif
+
+static VOID
+NTAPI
+DisplayCharacter(IN CHAR Character,
+ IN ULONG Left,
+ IN ULONG Top,
+ IN ULONG TextColor,
+ IN ULONG BackColor)
+{
+ PUCHAR FontChar, PixelPtr;
+ ULONG Height;
+ UCHAR Shift;
+
+ /* Switch to mode 10 */
+ ReadWriteMode(10);
+
+ /* Clear the 4 planes (we're already in unchained mode here) */
+ __outpw(0x3C4, 0xF02);
+
+ /* Select the color don't care register */
+ __outpw(0x3CE, 7);
+
+ /* Calculate shift */
+ Shift = Left & 7;
+
+ /* Get the font and pixel pointer */
+ FontChar = GetFontPtr(Character);
+ PixelPtr = (PUCHAR)(VgaBase + (Left >> 3) + (Top * 80));
+
+ /* Loop all pixel rows */
+ Height = BOOTCHAR_HEIGHT;
+ do
+ {
+ SET_PIXELS(PixelPtr, *FontChar >> Shift, TextColor);
+ PixelPtr += 80;
+ FontChar += FONT_PTR_DELTA;
+ } while (--Height);
+
+ /* Check if we need to update neighbor bytes */
+ if (Shift)
+ {
+ /* Calculate shift for 2nd byte */
+ Shift = 8 - Shift;
+
+ /* Get the font and pixel pointer (2nd byte) */
+ FontChar = GetFontPtr(Character);
+ PixelPtr = (PUCHAR)(VgaBase + (Left >> 3) + (Top * 80) + 1);
+
+ /* Loop all pixel rows */
+ Height = BOOTCHAR_HEIGHT;
+ do
+ {
+ SET_PIXELS(PixelPtr, *FontChar << Shift, TextColor);
+ PixelPtr += 80;
+ FontChar += FONT_PTR_DELTA;
+ } while (--Height);
+ }
+
+ /* Check if the background color is transparent */
+ if (BackColor >= 16)
+ {
+ /* We are done */
+ return;
+ }
+
+ /* Calculate shift */
+ Shift = Left & 7;
+
+ /* Get the font and pixel pointer */
+ FontChar = GetFontPtr(Character);
+ PixelPtr = (PUCHAR)(VgaBase + (Left >> 3) + (Top * 80));
+
+ /* Loop all pixel rows */
+ Height = BOOTCHAR_HEIGHT;
+ do
+ {
+ SET_PIXELS(PixelPtr, ~*FontChar >> Shift, BackColor);
+ PixelPtr += 80;
+ FontChar += FONT_PTR_DELTA;
+ } while (--Height);
+
+ /* Check if we need to update neighbor bytes */
+ if (Shift)
+ {
+ /* Calculate shift for 2nd byte */
+ Shift = 8 - Shift;
+
+ /* Get the font and pixel pointer (2nd byte) */
+ FontChar = GetFontPtr(Character);
+ PixelPtr = (PUCHAR)(VgaBase + (Left >> 3) + (Top * 80) + 1);
+
+ /* Loop all pixel rows */
+ Height = BOOTCHAR_HEIGHT;
+ do
+ {
+ SET_PIXELS(PixelPtr, ~*FontChar << Shift, BackColor);
+ PixelPtr += 80;
+ FontChar += FONT_PTR_DELTA;
+ } while (--Height);
+ }
+}
+
+static VOID
+NTAPI
+DisplayStringXY(IN PUCHAR String,
+ IN ULONG Left,
+ IN ULONG Top,
+ IN ULONG TextColor,
+ IN ULONG BackColor)
+{
+ /* Loop every character */
+ while (*String)
+ {
+ /* Display a character */
+ DisplayCharacter(*String, Left, Top, TextColor, BackColor);
+
+ /* Move to next character and next position */
+ String++;
+ Left += 8;
+ }
+}
+
+static VOID
+NTAPI
+SetPaletteEntryRGB(IN ULONG Id,
+ IN ULONG Rgb)
+{
+ PCHAR Colors = (PCHAR)&Rgb;
+
+ /* Set the palette index */
+ __outpb(0x3C8, (UCHAR)Id);
+
+ /* Set RGB colors */
+ __outpb(0x3C9, Colors[2] >> 2);
+ __outpb(0x3C9, Colors[1] >> 2);
+ __outpb(0x3C9, Colors[0] >> 2);
+}
+
+static VOID
+NTAPI
+InitPaletteWithTable(IN PULONG Table,
+ IN ULONG Count)
+{
+ ULONG i;
+ PULONG Entry = Table;
+
+ /* Loop every entry */
+ for (i = 0; i < Count; i++, Entry++)
+ {
+ /* Set the entry */
+ SetPaletteEntryRGB(i, *Entry);
+ }
+}
+
+static VOID
+NTAPI
+SetPaletteEntry(IN ULONG Id,
+ IN ULONG PaletteEntry)
+{
+ /* Set the palette index */
+ __outpb(0x3C8, (UCHAR)Id);
+
+ /* Set RGB colors */
+ __outpb(0x3C9, PaletteEntry & 0xFF);
+ __outpb(0x3C9, (PaletteEntry >>= 8) & 0xFF);
+ __outpb(0x3C9, (PaletteEntry >> 8) & 0xFF);
+}
+
+VOID
+NTAPI
+InitializePalette(VOID)
+{
+ ULONG PaletteEntry[16] = {0x000000,
+ 0x000020,
+ 0x002000,
+ 0x002020,
+ 0x200000,
+ 0x200020,
+ 0x202000,
+ 0x202020,
+ 0x303030,
+ 0x00003F,
+ 0x003F00,
+ 0x003F3F,
+ 0x3F0000,
+ 0x3F003F,
+ 0x3F3F00,
+ 0x3F3F3F};
+ ULONG i;
+
+ /* Loop all the entries and set their palettes */
+ for (i = 0; i < 16; i++) SetPaletteEntry(i, PaletteEntry[i]);
+}
+
+static VOID
+NTAPI
+VgaScroll(IN ULONG Scroll)
+{
+ ULONG Top, RowSize;
+ PUCHAR OldPosition, NewPosition;
+
+ /* Clear the 4 planes */
+ __outpw(0x3C4, 0xF02);
+
+ /* Set the bitmask to 0xFF for all 4 planes */
+ __outpw(0x3CE, 0xFF08);
+
+ /* Set Mode 1 */
+ ReadWriteMode(1);
+
+ RowSize = (ScrollRegion[2] - ScrollRegion[0] + 1) / 8;
+
+ /* Calculate the position in memory for the row */
+ OldPosition = (PUCHAR)(VgaBase + (ScrollRegion[1] + Scroll) * 80 + ScrollRegion[0] / 8);
+ NewPosition = (PUCHAR)(VgaBase + ScrollRegion[1] * 80 + ScrollRegion[0] / 8);
+
+ /* Start loop */
+ for (Top = ScrollRegion[1]; Top <= ScrollRegion[3]; ++Top)
+ {
+#if defined(_M_IX86) || defined(_M_AMD64)
+ __movsb(NewPosition, OldPosition, RowSize);
+#else
+ ULONG i;
+
+ /* Scroll the row */
+ for (i = 0; i < RowSize; ++i)
+ WRITE_REGISTER_UCHAR(NewPosition + i, READ_REGISTER_UCHAR(OldPosition + i));
+#endif
+ OldPosition += 80;
+ NewPosition += 80;
+ }
+}
+
+static VOID
+NTAPI
+PreserveRow(IN ULONG CurrentTop,
+ IN ULONG TopDelta,
+ IN BOOLEAN Direction)
+{
+ PUCHAR Position1, Position2;
+ ULONG Count;
+
+ /* Clear the 4 planes */
+ __outpw(0x3C4, 0xF02);
+
+ /* Set the bitmask to 0xFF for all 4 planes */
+ __outpw(0x3CE, 0xFF08);
+
+ /* Set Mode 1 */
+ ReadWriteMode(1);
+
+ /* Check which way we're preserving */
+ if (Direction)
+ {
+ /* Calculate the position in memory for the row */
+ Position1 = (PUCHAR)(VgaBase + CurrentTop * 80);
+ Position2 = (PUCHAR)(VgaBase + 0x9600);
+ }
+ else
+ {
+ /* Calculate the position in memory for the row */
+ Position1 = (PUCHAR)(VgaBase + 0x9600);
+ Position2 = (PUCHAR)(VgaBase + CurrentTop * 80);
+ }
+
+ /* Set the count and loop every pixel */
+ Count = TopDelta * 80;
+
+#if defined(_M_IX86) || defined(_M_AMD64)
+ __movsb(Position1, Position2, Count);
+#else
+ while (Count--)
+ {
+ /* Write the data back on the other position */
+ WRITE_REGISTER_UCHAR(Position1, READ_REGISTER_UCHAR(Position2));
+
+ /* Increase both positions */
+ Position1++;
+ Position2++;
+ }
+#endif
+}
+
+static VOID
+NTAPI
+BitBlt(IN ULONG Left,
+ IN ULONG Top,
+ IN ULONG Width,
+ IN ULONG Height,
+ IN PUCHAR Buffer,
+ IN ULONG BitsPerPixel,
+ IN ULONG Delta)
+{
+ ULONG sx, dx, dy;
+ UCHAR color;
+ ULONG offset = 0;
+ const ULONG Bottom = Top + Height;
+ const ULONG Right = Left + Width;
+
+ /* Check if the buffer isn't 4bpp */
+ if (BitsPerPixel != 4)
+ {
+ /* FIXME: TODO */
+ DbgPrint("Unhandled BitBlt\n"
+ "%lux%lu @ (%lu|%lu)\n"
+ "Bits Per Pixel %lu\n"
+ "Buffer: %p. Delta: %lu\n",
+ Width,
+ Height,
+ Left,
+ Top,
+ BitsPerPixel,
+ Buffer,
+ Delta);
+ return;
+ }
+
+ /* Switch to mode 10 */
+ ReadWriteMode(10);
+
+ /* Clear the 4 planes (we're already in unchained mode here) */
+ __outpw(0x3C4, 0xF02);
+
+ /* Select the color don't care register */
+ __outpw(0x3CE, 7);
+
+ /* 4bpp blitting */
+ dy = Top;
+ do
+ {
+ sx = 0;
+ do
+ {
+ /* Extract color */
+ color = Buffer[offset + sx];
+
+ /* Calc destination x */
+ dx = Left + (sx << 1);
+
+ /* Set two pixels */
+ SetPixel(dx, dy, color >> 4);
+ SetPixel(dx + 1, dy, color & 0x0F);
+
+ sx++;
+ } while (dx < Right);
+ offset += Delta;
+ dy++;
+ } while (dy < Bottom);
+}
+
+static VOID
+NTAPI
+RleBitBlt(IN ULONG Left,
+ IN ULONG Top,
+ IN ULONG Width,
+ IN ULONG Height,
+ IN PUCHAR Buffer)
+{
+ ULONG YDelta;
+ ULONG x;
+ ULONG RleValue, NewRleValue;
+ ULONG Color, Color2;
+ ULONG i, j;
+ ULONG Code;
+
+ /* Switch to mode 10 */
+ ReadWriteMode(10);
+
+ /* Clear the 4 planes (we're already in unchained mode here) */
+ __outpw(0x3C4, 0xF02);
+
+ /* Select the color don't care register */
+ __outpw(0x3CE, 7);
+
+ /* Set Y height and current X value and start loop */
+ YDelta = Top + Height - 1;
+ x = Left;
+ for (;;)
+ {
+ /* Get the current value and advance in the buffer */
+ RleValue = *Buffer;
+ Buffer++;
+ if (RleValue)
+ {
+ /* Check if we've gone past the edge */
+ if ((x + RleValue) > (Width + Left))
+ {
+ /* Fixup the pixel value */
+ RleValue = Left - x + Width;
+ }
+
+ /* Get the new value */
+ NewRleValue = *Buffer;
+
+ /* Get the two colors */
+ Color = NewRleValue >> 4;
+ Color2 = NewRleValue & 0xF;
+
+ /* Increase buffer position */
+ Buffer++;
+
+ /* Check if we need to do a fill */
+ if (Color == Color2)
+ {
+ /* Do a fill and continue the loop */
+ RleValue += x;
+ VidSolidColorFill(x, YDelta, RleValue - 1, YDelta, (UCHAR)Color);
+ x = RleValue;
+ continue;
+ }
+
+ /* Check if the pixel value is 1 or below */
+ if (RleValue > 1)
+ {
+ /* Set loop variables */
+ i = (RleValue - 2) / 2 + 1;
+ do
+ {
+ /* Set the pixels */
+ SetPixel(x, YDelta, (UCHAR)Color);
+ x++;
+ SetPixel(x, YDelta, (UCHAR)Color2);
+ x++;
+
+ /* Decrease pixel value */
+ RleValue -= 2;
+ } while (--i);
+ }
+
+ /* Check if there is any value at all */
+ if (RleValue)
+ {
+ /* Set the pixel and increase position */
+ SetPixel(x, YDelta, (UCHAR)Color);
+ x++;
+ }
+
+ /* Start over */
+ continue;
+ }
+
+ /* Get the current pixel value */
+ RleValue = *Buffer;
+ Code = RleValue;
+ switch (Code)
+ {
+ /* Case 0 */
+ case 0:
+ {
+ /* Set new x value, decrease distance and restart */
+ x = Left;
+ YDelta--;
+ Buffer++;
+ continue;
+ }
+
+ /* Case 1 */
+ case 1:
+ {
+ /* Done */
+ return;
+ }
+
+ /* Case 2 */
+ case 2:
+ {
+ /* Set new x value, decrease distance and restart */
+ Buffer++;
+ x += *Buffer;
+ Buffer++;
+ YDelta -= *Buffer;
+ Buffer++;
+ continue;
+ }
+
+ /* Other values */
+ default:
+ {
+ Buffer++;
+ break;
+ }
+ }
+
+ /* Check if we've gone past the edge */
+ if ((x + RleValue) > (Width + Left))
+ {
+ /* Set fixed up loop count */
+ i = RleValue - Left - Width + x;
+
+ /* Fixup pixel value */
+ RleValue -= i;
+ }
+ else
+ {
+ /* Clear loop count */
+ i = 0;
+ }
+
+ /* Check the value now */
+ if (RleValue > 1)
+ {
+ /* Set loop variables */
+ j = (RleValue - 2) / 2 + 1;
+ do
+ {
+ /* Get the new value */
+ NewRleValue = *Buffer;
+
+ /* Get the two colors */
+ Color = NewRleValue >> 4;
+ Color2 = NewRleValue & 0xF;
+
+ /* Increase buffer position */
+ Buffer++;
+
+ /* Set the pixels */
+ SetPixel(x, YDelta, (UCHAR)Color);
+ x++;
+ SetPixel(x, YDelta, (UCHAR)Color2);
+ x++;
+
+ /* Decrease pixel value */
+ RleValue -= 2;
+ } while (--j);
+ }
+
+ /* Check if there is any value at all */
+ if (RleValue)
+ {
+ /* Set the pixel and increase position */
+ Color = *Buffer >> 4;
+ Buffer++;
+ SetPixel(x, YDelta, (UCHAR)Color);
+ x++;
+ i--;
+ }
+
+ /* Check loop count now */
+ if ((LONG)i > 0)
+ {
+ /* Decrease it */
+ i--;
+
+ /* Set new position */
+ Buffer = Buffer + (i / 2) + 1;
+ }
+
+ /* Check if we need to increase the buffer */
+ if ((ULONG_PTR)Buffer & 1) Buffer++;
+ }
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*
+ * @implemented
+ */
+ULONG
+NTAPI
+VidSetTextColor(IN ULONG Color)
+{
+ ULONG OldColor;
+
+ /* Save the old color and set the new one */
+ OldColor = VidTextColor;
+ VidTextColor = Color;
+ return OldColor;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+VidDisplayStringXY(IN PUCHAR String,
+ IN ULONG Left,
+ IN ULONG Top,
+ IN BOOLEAN Transparent)
+{
+ ULONG BackColor;
+
+ /*
+ * If the caller wanted transparent, then send the special value (16),
+ * else use our default and call the helper routine.
+ */
+ BackColor = Transparent ? 16 : 14;
+ DisplayStringXY(String, Left, Top, 12, BackColor);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+VidSetScrollRegion(IN ULONG Left,
+ IN ULONG Top,
+ IN ULONG Right,
+ IN ULONG Bottom)
+{
+ /* Assert alignment */
+ ASSERT((Left & 0x7) == 0);
+ ASSERT((Right & 0x7) == 7);
+
+ /* Set Scroll Region */
+ ScrollRegion[0] = Left;
+ ScrollRegion[1] = Top;
+ ScrollRegion[2] = Right;
+ ScrollRegion[3] = Bottom;
+
+ /* Set current X and Y */
+ curr_x = Left;
+ curr_y = Top;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+VidCleanUp(VOID)
+{
+ /* Select bit mask register */
+ WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 8);
+
+ /* Clear it */
+ WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 255);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+VidBufferToScreenBlt(IN PUCHAR Buffer,
+ IN ULONG Left,
+ IN ULONG Top,
+ IN ULONG Width,
+ IN ULONG Height,
+ IN ULONG Delta)
+{
+ /* Make sure we have a width and height */
+ if (!Width || !Height) return;
+
+ /* Call the helper function */
+ BitBlt(Left, Top, Width, Height, Buffer, 4, Delta);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+VidDisplayString(IN PUCHAR String)
+{
+ ULONG TopDelta = BOOTCHAR_HEIGHT + 1;
+
+ /* Start looping the string */
+ while (*String)
+ {
+ /* Treat new-line separately */
+ if (*String == '\n')
+ {
+ /* Modify Y position */
+ curr_y += TopDelta;
+ if (curr_y + TopDelta >= ScrollRegion[3])
+ {
+ /* Scroll the view */
+ VgaScroll(TopDelta);
+ curr_y -= TopDelta;
+ }
+ else
+ {
+ /* Preserve row */
+ PreserveRow(curr_y, TopDelta, FALSE);
+ }
+
+ /* Update current X */
+ curr_x = ScrollRegion[0];
+
+ /* Do not clear line if "\r\n" is given */
+ CarriageReturn = FALSE;
+ }
+ else if (*String == '\r')
+ {
+ /* Update current X */
+ curr_x = ScrollRegion[0];
+
+ /* Check if we're being followed by a new line */
+ CarriageReturn = TRUE;
+ }
+ else
+ {
+ /* check if we had a '\r' last time */
+ if (CarriageReturn)
+ {
+ /* We did, clear the current row */
+ PreserveRow(curr_y, TopDelta, TRUE);
+ CarriageReturn = FALSE;
+ }
+
+ /* Display this character */
+ DisplayCharacter(*String, curr_x, curr_y, VidTextColor, 16);
+ curr_x += 8;
+
+ /* Check if we should scroll */
+ if (curr_x + 8 > ScrollRegion[2])
+ {
+ /* Update Y position and check if we should scroll it */
+ curr_y += TopDelta;
+ if (curr_y + TopDelta > ScrollRegion[3])
+ {
+ /* Do the scroll */
+ VgaScroll(TopDelta);
+ curr_y -= TopDelta;
+ }
+ else
+ {
+ /* Preserve the current row */
+ PreserveRow(curr_y, TopDelta, FALSE);
+ }
+
+ /* Update X */
+ curr_x = ScrollRegion[0];
+ }
+ }
+
+ /* Get the next character */
+ String++;
+ }
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+VidBitBlt(IN PUCHAR Buffer,
+ IN ULONG Left,
+ IN ULONG Top)
+{
+ PBITMAPINFOHEADER BitmapInfoHeader;
+ LONG Delta;
+ PUCHAR BitmapOffset;
+
+ /* Get the Bitmap Header */
+ BitmapInfoHeader = (PBITMAPINFOHEADER)Buffer;
+
+ /* Initialize the palette */
+ InitPaletteWithTable((PULONG)(Buffer + BitmapInfoHeader->biSize),
+ (BitmapInfoHeader->biClrUsed) ?
+ BitmapInfoHeader->biClrUsed : 16);
+
+ /* Make sure we can support this bitmap */
+ ASSERT((BitmapInfoHeader->biBitCount * BitmapInfoHeader->biPlanes) <= 4);
+
+ /*
+ * Calculate the delta and align it on 32-bytes, then calculate
+ * the actual start of the bitmap data.
+ */
+ Delta = (BitmapInfoHeader->biBitCount * BitmapInfoHeader->biWidth) + 31;
+ Delta >>= 3;
+ Delta &= ~3;
+ BitmapOffset = Buffer + sizeof(BITMAPINFOHEADER) + 16 * sizeof(ULONG);
+
+ /* Check the compression of the bitmap */
+ if (BitmapInfoHeader->biCompression == BI_RLE4)
+ {
+ /* Make sure we have a width and a height */
+ if ((BitmapInfoHeader->biWidth) && (BitmapInfoHeader->biHeight))
+ {
+ /* We can use RLE Bit Blt */
+ RleBitBlt(Left,
+ Top,
+ BitmapInfoHeader->biWidth,
+ BitmapInfoHeader->biHeight,
+ BitmapOffset);
+ }
+ }
+ else
+ {
+ /* Check if the height is negative */
+ if (BitmapInfoHeader->biHeight < 0)
+ {
+ /* Make it positive in the header */
+ BitmapInfoHeader->biHeight *= -1;
+ }
+ else
+ {
+ /* Update buffer offset */
+ BitmapOffset += ((BitmapInfoHeader->biHeight - 1) * Delta);
+ Delta *= -1;
+ }
+
+ /* Make sure we have a width and a height */
+ if ((BitmapInfoHeader->biWidth) && (BitmapInfoHeader->biHeight))
+ {
+ /* Do the BitBlt */
+ BitBlt(Left,
+ Top,
+ BitmapInfoHeader->biWidth,
+ BitmapInfoHeader->biHeight,
+ BitmapOffset,
+ BitmapInfoHeader->biBitCount,
+ Delta);
+ }
+ }
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+VidScreenToBufferBlt(IN PUCHAR Buffer,
+ IN ULONG Left,
+ IN ULONG Top,
+ IN ULONG Width,
+ IN ULONG Height,
+ IN ULONG Delta)
+{
+ ULONG Plane;
+ ULONG XDistance;
+ ULONG LeftDelta, RightDelta;
+ ULONG PixelOffset;
+ PUCHAR PixelPosition;
+ PUCHAR k, i;
+ PULONG m;
+ UCHAR Value, Value2;
+ UCHAR a;
+ ULONG b;
+ ULONG x, y;
+
+ /* Calculate total distance to copy on X */
+ XDistance = Left + Width - 1;
+
+ /* Start at plane 0 */
+ Plane = 0;
+
+ /* Calculate the 8-byte left and right deltas */
+ LeftDelta = Left & 7;
+ RightDelta = 8 - LeftDelta;
+
+ /* Clear the destination buffer */
+ RtlZeroMemory(Buffer, Delta * Height);
+
+ /* Calculate the pixel offset and convert the X distance into byte form */
+ PixelOffset = Top * 80 + (Left >> 3);
+ XDistance >>= 3;
+
+ /* Loop the 4 planes */
+ do
+ {
+ /* Set the current pixel position and reset buffer loop variable */
+ PixelPosition = (PUCHAR)(VgaBase + PixelOffset);
+ i = Buffer;
+
+ /* Set Mode 0 */
+ ReadWriteMode(0);
+
+ /* Set the current plane */
+ __outpw(0x3CE, (Plane << 8) | 4);
+
+ /* Make sure we have a height */
+ if (Height > 0)
+ {
+ /* Start the outer Y loop */
+ y = Height;
+ do
+ {
+ /* Read the current value */
+ m = (PULONG)i;
+ Value = READ_REGISTER_UCHAR(PixelPosition);
+
+ /* Set Pixel Position loop variable */
+ k = PixelPosition + 1;
+
+ /* Check if we're still within bounds */
+ if (Left <= XDistance)
+ {
+ /* Start X Inner loop */
+ x = (XDistance - Left) + 1;
+ do
+ {
+ /* Read the current value */
+ Value2 = READ_REGISTER_UCHAR(k);
+
+ /* Increase pixel position */
+ k++;
+
+ /* Do the blt */
+ a = Value2 >> (UCHAR)RightDelta;
+ a |= Value << (UCHAR)LeftDelta;
+ b = lookup[a & 0xF];
+ a >>= 4;
+ b <<= 16;
+ b |= lookup[a];
+
+ /* Save new value to buffer */
+ *m |= (b << Plane);
+
+ /* Move to next destination location */
+ m++;
+
+ /* Write new value */
+ Value = Value2;
+ } while (--x);
+ }
+
+ /* Update pixel position */
+ PixelPosition += 80;
+ i += Delta;
+ } while (--y);
+ }
+ } while (++Plane < 4);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+VidSolidColorFill(IN ULONG Left,
+ IN ULONG Top,
+ IN ULONG Right,
+ IN ULONG Bottom,
+ IN UCHAR Color)
+{
+ ULONG rMask, lMask;
+ ULONG LeftOffset, RightOffset, Distance;
+ PUCHAR Offset;
+ ULONG i, j;
+
+ /* Get the left and right masks, shifts, and delta */
+ LeftOffset = Left >> 3;
+ lMask = (lMaskTable[Left & 0x7] << 8) | 8;
+ RightOffset = Right >> 3;
+ rMask = (rMaskTable[Right & 0x7] << 8) | 8;
+ Distance = RightOffset - LeftOffset;
+
+ /* If there is no distance, then combine the right and left masks */
+ if (!Distance) lMask &= rMask;
+
+ /* Switch to mode 10 */
+ ReadWriteMode(10);
+
+ /* Clear the 4 planes (we're already in unchained mode here) */
+ __outpw(0x3C4, 0xF02);
+
+ /* Select the color don't care register */
+ __outpw(0x3CE, 7);
+
+ /* Calculate pixel position for the read */
+ Offset = (PUCHAR)(VgaBase + (Top * 80) + LeftOffset);
+
+ /* Select the bitmask register and write the mask */
+ __outpw(0x3CE, (USHORT)lMask);
+
+ /* Check if the top coord is below the bottom one */
+ if (Top <= Bottom)
+ {
+ /* Start looping each line */
+ i = (Bottom - Top) + 1;
+ do
+ {
+ /* Read the previous value and add our color */
+ WRITE_REGISTER_UCHAR(Offset, READ_REGISTER_UCHAR(Offset) & Color);
+
+ /* Move to the next line */
+ Offset += 80;
+ } while (--i);
+ }
+
+ /* Check if we have a delta */
+ if (Distance)
+ {
+ /* Calculate new pixel position */
+ Offset = (PUCHAR)(VgaBase + (Top * 80) + RightOffset);
+ Distance--;
+
+ /* Select the bitmask register and write the mask */
+ __outpw(0x3CE, (USHORT)rMask);
+
+ /* Check if the top coord is below the bottom one */
+ if (Top <= Bottom)
+ {
+ /* Start looping each line */
+ i = (Bottom - Top) + 1;
+ do
+ {
+ /* Read the previous value and add our color */
+ WRITE_REGISTER_UCHAR(Offset,
+ READ_REGISTER_UCHAR(Offset) & Color);
+
+ /* Move to the next line */
+ Offset += 80;
+ } while (--i);
+ }
+
+ /* Check if we still have a delta */
+ if (Distance)
+ {
+ /* Calculate new pixel position */
+ Offset = (PUCHAR)(VgaBase + (Top * 80) + LeftOffset + 1);
+
+ /* Set the bitmask to 0xFF for all 4 planes */
+ __outpw(0x3CE, 0xFF08);
+
+ /* Check if the top coord is below the bottom one */
+ if (Top <= Bottom)
+ {
+ /* Start looping each line */
+ i = (Bottom - Top) + 1;
+ do
+ {
+ /* Loop the shift delta */
+ if (Distance > 0)
+ {
+ for (j = Distance; j; Offset++, j--)
+ {
+ /* Write the color */
+ WRITE_REGISTER_UCHAR(Offset, Color);
+ }
+ }
+
+ /* Update position in memory */
+ Offset += (80 - Distance);
+ } while (--i);
+ }
+ }
+ }
+}