[NTOSKRNL][HAL][BOOTVID] Some more code refactoring

- Add boot video color constants
- Refactor palette initialization
- Move some common stuff in right place
- Get rid of some magic constants and hardcoded values
- Get rid of TopDelta variable (calculated at compile time)
- Update SAL annotations

Addendum to 5f2ca473. CORE-16216 CORE-16219
This commit is contained in:
Stanislav Motylkov 2020-05-09 17:20:57 +03:00
parent 909f50a857
commit cd91271796
No known key found for this signature in database
GPG key ID: AFE513258CBA9E92
15 changed files with 367 additions and 426 deletions

View file

@ -23,41 +23,28 @@ extern PUSHORT VgaArmBase;
#define READ_REGISTER_USHORT(r) (*(volatile USHORT * const)(r)) #define READ_REGISTER_USHORT(r) (*(volatile USHORT * const)(r))
#define WRITE_REGISTER_USHORT(r, v) (*(volatile USHORT *)(r) = (v)) #define WRITE_REGISTER_USHORT(r, v) (*(volatile USHORT *)(r) = (v))
PALETTE_ENTRY VidpVga8To16BitTransform[16] =
{
{0x00, 0x00, 0x00}, // Black
{0x00, 0x00, 0x08}, // Blue
{0x00, 0x08, 0x00}, // Green
{0x00, 0x08, 0x08}, // Cyan
{0x08, 0x00, 0x00}, // Red
{0x08, 0x00, 0x08}, // Magenta
{0x0B, 0x0D, 0x0F}, // Brown
{0x10, 0x10, 0x10}, // Light Gray
{0x08, 0x08, 0x08}, // Dark Gray
{0x00, 0x00, 0x1F}, // Light Blue
{0x00, 0x1F, 0x00}, // Light Green
{0x00, 0x1F, 0x1F}, // Light Cyan
{0x1F, 0x00, 0x00}, // Light Red
{0x1F, 0x00, 0x1F}, // Light Magenta
{0x1F, 0x1F, 0x00}, // Yellow
{0x1F, 0x1F, 0x1F}, // White
};
FORCEINLINE FORCEINLINE
USHORT USHORT
VidpBuildColor(_In_ UCHAR Color) VidpBuildColor(
_In_ UCHAR Color)
{ {
UCHAR Red, Green, Blue; UCHAR Red, Green, Blue;
/* Extract color components */ /* Extract color components */
Red = VidpVga8To16BitTransform[Color].Red; Red = GetRValue(DefaultPalette[Color]) >> 3;
Green = VidpVga8To16BitTransform[Color].Green; Green = GetGValue(DefaultPalette[Color]) >> 3;
Blue = VidpVga8To16BitTransform[Color].Blue; Blue = GetBValue(DefaultPalette[Color]) >> 3;
/* Build the 16-bit color mask */ /* Build the 16-bit color mask */
return ((Red & 0x1F) << 11) | ((Green & 0x1F) << 6) | ((Blue & 0x1F)); return ((Red & 0x1F) << 11) | ((Green & 0x1F) << 6) | ((Blue & 0x1F));
} }
VOID
NTAPI
InitPaletteWithTable(
_In_ PULONG Table,
_In_ ULONG Count);
FORCEINLINE FORCEINLINE
VOID VOID
SetPixel( SetPixel(
@ -73,3 +60,24 @@ SetPixel(
/* Set our color */ /* Set our color */
WRITE_REGISTER_USHORT(PixelPosition, VidpBuildColor(Color)); WRITE_REGISTER_USHORT(PixelPosition, VidpBuildColor(Color));
} }
VOID
NTAPI
PreserveRow(
_In_ ULONG CurrentTop,
_In_ ULONG TopDelta,
_In_ BOOLEAN Restore);
VOID
NTAPI
DoScroll(
_In_ ULONG Scroll);
VOID
NTAPI
DisplayCharacter(
_In_ CHAR Character,
_In_ ULONG Left,
_In_ ULONG Top,
_In_ ULONG TextColor,
_In_ ULONG BackColor);

View file

@ -5,23 +5,23 @@
PUSHORT VgaArmBase; PUSHORT VgaArmBase;
PHYSICAL_ADDRESS VgaPhysical; PHYSICAL_ADDRESS VgaPhysical;
BOOLEAN ClearRow = FALSE;
/* PRIVATE FUNCTIONS *********************************************************/ /* PRIVATE FUNCTIONS *********************************************************/
VOID VOID
NTAPI NTAPI
DisplayCharacter(IN CHAR Character, DisplayCharacter(
IN ULONG Left, _In_ CHAR Character,
IN ULONG Top, _In_ ULONG Left,
IN ULONG TextColor, _In_ ULONG Top,
IN ULONG BackColor) _In_ ULONG TextColor,
_In_ ULONG BackColor)
{ {
PUCHAR FontChar; PUCHAR FontChar;
ULONG i, j, XOffset; ULONG i, j, XOffset;
/* Get the font line for this character */ /* Get the font line for this character */
FontChar = &FontData[Character * BOOTCHAR_HEIGHT - Top]; FontChar = &VidpFontData[Character * BOOTCHAR_HEIGHT - Top];
/* Loop each pixel height */ /* Loop each pixel height */
for (i = BOOTCHAR_HEIGHT; i > 0; --i) for (i = BOOTCHAR_HEIGHT; i > 0; --i)
@ -36,7 +36,7 @@ DisplayCharacter(IN CHAR Character,
/* We do, use the given Text Color */ /* We do, use the given Text Color */
SetPixel(XOffset, Top, (UCHAR)TextColor); SetPixel(XOffset, Top, (UCHAR)TextColor);
} }
else if (BackColor < 16) else if (BackColor < BV_COLOR_NONE)
{ {
/* /*
* This is a background pixel. We're drawing it * This is a background pixel. We're drawing it
@ -56,7 +56,8 @@ DisplayCharacter(IN CHAR Character,
VOID VOID
NTAPI NTAPI
VgaScroll(IN ULONG Scroll) DoScroll(
_In_ ULONG Scroll)
{ {
ULONG Top, Offset; ULONG Top, Offset;
PUSHORT SourceOffset, DestOffset; PUSHORT SourceOffset, DestOffset;
@ -103,9 +104,10 @@ VgaScroll(IN ULONG Scroll)
VOID VOID
NTAPI NTAPI
PreserveRow(IN ULONG CurrentTop, PreserveRow(
IN ULONG TopDelta, _In_ ULONG CurrentTop,
IN BOOLEAN Restore) _In_ ULONG TopDelta,
_In_ BOOLEAN Restore)
{ {
PUSHORT Position1, Position2; PUSHORT Position1, Position2;
ULONG Count; ULONG Count;
@ -179,7 +181,8 @@ InitPaletteWithTable(
*/ */
BOOLEAN BOOLEAN
NTAPI NTAPI
VidInitialize(IN BOOLEAN SetMode) VidInitialize(
_In_ BOOLEAN SetMode)
{ {
DPRINT1("bv-arm v0.1\n"); DPRINT1("bv-arm v0.1\n");
@ -214,7 +217,8 @@ VidInitialize(IN BOOLEAN SetMode)
*/ */
VOID VOID
NTAPI NTAPI
VidResetDisplay(IN BOOLEAN HalReset) VidResetDisplay(
_In_ BOOLEAN HalReset)
{ {
// //
// Clear the current position // Clear the current position
@ -230,29 +234,8 @@ VidResetDisplay(IN BOOLEAN HalReset)
// //
// Re-initialize the palette and fill the screen black // Re-initialize the palette and fill the screen black
// //
//InitializePalette(); InitializePalette();
VidSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, 0); VidSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLACK);
}
/*
* @implemented
*/
ULONG
NTAPI
VidSetTextColor(IN ULONG Color)
{
UCHAR OldColor;
//
// Save the old, set the new
//
OldColor = VidpTextColor;
VidpTextColor = Color;
//
// Return the old text color
//
return OldColor;
} }
/* /*
@ -271,98 +254,13 @@ VidCleanUp(VOID)
*/ */
VOID VOID
NTAPI NTAPI
VidDisplayString(IN PUCHAR String) VidScreenToBufferBlt(
{ _Out_ PUCHAR Buffer,
ULONG TopDelta = BOOTCHAR_HEIGHT + 1; _In_ ULONG Left,
_In_ ULONG Top,
/* Start looping the string */ _In_ ULONG Width,
for (; *String; ++String) _In_ ULONG Height,
{ _In_ ULONG Delta)
/* Treat new-line separately */
if (*String == '\n')
{
/* Modify Y position */
VidpCurrentY += TopDelta;
if (VidpCurrentY + TopDelta - 1 > VidpScrollRegion[3])
{
/* Scroll the view and clear the current row */
VgaScroll(TopDelta);
VidpCurrentY -= TopDelta;
PreserveRow(VidpCurrentY, TopDelta, TRUE);
}
else
{
/* Preserve the current row */
PreserveRow(VidpCurrentY, TopDelta, FALSE);
}
/* Update current X */
VidpCurrentX = VidpScrollRegion[0];
/* No need to clear this row */
ClearRow = FALSE;
}
else if (*String == '\r')
{
/* Update current X */
VidpCurrentX = VidpScrollRegion[0];
/* If a new-line does not follow we will clear the current row */
if (String[1] != '\n') ClearRow = TRUE;
}
else
{
/* Clear the current row if we had a return-carriage without a new-line */
if (ClearRow)
{
PreserveRow(VidpCurrentY, TopDelta, TRUE);
ClearRow = FALSE;
}
/* Display this character */
DisplayCharacter(*String,
VidpCurrentX,
VidpCurrentY,
VidpTextColor,
16);
VidpCurrentX += 8;
/* Check if we should scroll */
if (VidpCurrentX + 7 > VidpScrollRegion[2])
{
/* Update Y position and check if we should scroll it */
VidpCurrentY += TopDelta;
if (VidpCurrentY + TopDelta - 1 > VidpScrollRegion[3])
{
/* Scroll the view and clear the current row */
VgaScroll(TopDelta);
VidpCurrentY -= TopDelta;
PreserveRow(VidpCurrentY, TopDelta, TRUE);
}
else
{
/* Preserve the current row */
PreserveRow(VidpCurrentY, TopDelta, FALSE);
}
/* Update current X */
VidpCurrentX = VidpScrollRegion[0];
}
}
}
}
/*
* @implemented
*/
VOID
NTAPI
VidScreenToBufferBlt(OUT PUCHAR Buffer,
IN ULONG Left,
IN ULONG Top,
IN ULONG Width,
IN ULONG Height,
IN ULONG Delta)
{ {
UNIMPLEMENTED; UNIMPLEMENTED;
while (TRUE); while (TRUE);
@ -373,11 +271,12 @@ VidScreenToBufferBlt(OUT PUCHAR Buffer,
*/ */
VOID VOID
NTAPI NTAPI
VidSolidColorFill(IN ULONG Left, VidSolidColorFill(
IN ULONG Top, _In_ ULONG Left,
IN ULONG Right, _In_ ULONG Top,
IN ULONG Bottom, _In_ ULONG Right,
IN UCHAR Color) _In_ ULONG Bottom,
_In_ UCHAR Color)
{ {
int y, x; int y, x;

View file

@ -2,7 +2,7 @@
/* GLOBALS ********************************************************************/ /* GLOBALS ********************************************************************/
UCHAR VidpTextColor = 0x0F; UCHAR VidpTextColor = BV_COLOR_WHITE;
ULONG VidpCurrentX = 0; ULONG VidpCurrentX = 0;
ULONG VidpCurrentY = 0; ULONG VidpCurrentY = 0;
@ -15,6 +15,33 @@ ULONG VidpScrollRegion[4] =
SCREEN_HEIGHT - 1 SCREEN_HEIGHT - 1
}; };
/*
* Boot video driver default palette is similar to the standard 16-color
* CGA palette, but it has Red and Blue channels swapped, and also dark
* and light gray colors swapped.
*/
const RGBQUAD VidpDefaultPalette[BV_MAX_COLORS] =
{
RGB( 0, 0, 0), /* Black */
RGB(128, 0, 0), /* Red */
RGB( 0, 128, 0), /* Green */
RGB(128, 128, 0), /* Brown */
RGB( 0, 0, 128), /* Blue */
RGB(128, 0, 128), /* Magenta */
RGB( 0, 128, 128), /* Cyan */
RGB(128, 128, 128), /* Dark Gray */
RGB(192, 192, 192), /* Light Gray */
RGB(255, 0, 0), /* Light Red */
RGB( 0, 255, 0), /* Light Green */
RGB(255, 255, 0), /* Yellow */
RGB( 0, 0, 255), /* Light Blue */
RGB(255, 0, 255), /* Light Magenta */
RGB( 0, 255, 255), /* Light Cyan */
RGB(255, 255, 255), /* White */
};
static BOOLEAN ClearRow = FALSE;
/* PRIVATE FUNCTIONS **********************************************************/ /* PRIVATE FUNCTIONS **********************************************************/
static VOID static VOID
@ -272,6 +299,22 @@ RleBitBlt(
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/
/*
* @implemented
*/
ULONG
NTAPI
VidSetTextColor(
_In_ ULONG Color)
{
ULONG OldColor;
/* Save the old color and set the new one */
OldColor = VidpTextColor;
VidpTextColor = Color;
return OldColor;
}
VOID VOID
NTAPI NTAPI
VidDisplayStringXY( VidDisplayStringXY(
@ -286,13 +329,13 @@ VidDisplayStringXY(
* If the caller wanted transparent, then send the special value (16), * If the caller wanted transparent, then send the special value (16),
* else use our default and call the helper routine. * else use our default and call the helper routine.
*/ */
BackColor = Transparent ? 16 : 14; BackColor = Transparent ? BV_COLOR_NONE : BV_COLOR_LIGHT_CYAN;
/* Loop every character and adjust the position */ /* Loop every character and adjust the position */
for (; *String; ++String, Left += 8) for (; *String; ++String, Left += BOOTCHAR_WIDTH)
{ {
/* Display a character */ /* Display a character */
DisplayCharacter(*String, Left, Top, 12, BackColor); DisplayCharacter(*String, Left, Top, BV_COLOR_LIGHT_BLUE, BackColor);
} }
} }
@ -305,8 +348,8 @@ VidSetScrollRegion(
_In_ ULONG Bottom) _In_ ULONG Bottom)
{ {
/* Assert alignment */ /* Assert alignment */
ASSERT((Left & 0x7) == 0); ASSERT((Left % BOOTCHAR_WIDTH) == 0);
ASSERT((Right & 0x7) == 7); ASSERT((Right % BOOTCHAR_WIDTH) == BOOTCHAR_WIDTH - 1);
/* Set Scroll Region */ /* Set Scroll Region */
VidpScrollRegion[0] = Left; VidpScrollRegion[0] = Left;
@ -319,6 +362,87 @@ VidSetScrollRegion(
VidpCurrentY = Top; VidpCurrentY = Top;
} }
/*
* @implemented
*/
VOID
NTAPI
VidDisplayString(
_In_ PUCHAR String)
{
/* Start looping the string */
for (; *String; ++String)
{
/* Treat new-line separately */
if (*String == '\n')
{
/* Modify Y position */
VidpCurrentY += BOOTCHAR_HEIGHT + 1;
if (VidpCurrentY + BOOTCHAR_HEIGHT > VidpScrollRegion[3])
{
/* Scroll the view and clear the current row */
DoScroll(BOOTCHAR_HEIGHT + 1);
VidpCurrentY -= BOOTCHAR_HEIGHT + 1;
PreserveRow(VidpCurrentY, BOOTCHAR_HEIGHT + 1, TRUE);
}
else
{
/* Preserve the current row */
PreserveRow(VidpCurrentY, BOOTCHAR_HEIGHT + 1, FALSE);
}
/* Update current X */
VidpCurrentX = VidpScrollRegion[0];
/* No need to clear this row */
ClearRow = FALSE;
}
else if (*String == '\r')
{
/* Update current X */
VidpCurrentX = VidpScrollRegion[0];
/* If a new-line does not follow we will clear the current row */
if (String[1] != '\n') ClearRow = TRUE;
}
else
{
/* Clear the current row if we had a return-carriage without a new-line */
if (ClearRow)
{
PreserveRow(VidpCurrentY, BOOTCHAR_HEIGHT + 1, TRUE);
ClearRow = FALSE;
}
/* Display this character */
DisplayCharacter(*String, VidpCurrentX, VidpCurrentY, VidpTextColor, BV_COLOR_NONE);
VidpCurrentX += BOOTCHAR_WIDTH;
/* Check if we should scroll */
if (VidpCurrentX + BOOTCHAR_WIDTH - 1 > VidpScrollRegion[2])
{
/* Update Y position and check if we should scroll it */
VidpCurrentY += BOOTCHAR_HEIGHT + 1;
if (VidpCurrentY + BOOTCHAR_HEIGHT > VidpScrollRegion[3])
{
/* Scroll the view and clear the current row */
DoScroll(BOOTCHAR_HEIGHT + 1);
VidpCurrentY -= BOOTCHAR_HEIGHT + 1;
PreserveRow(VidpCurrentY, BOOTCHAR_HEIGHT + 1, TRUE);
}
else
{
/* Preserve the current row */
PreserveRow(VidpCurrentY, BOOTCHAR_HEIGHT + 1, FALSE);
}
/* Update current X */
VidpCurrentX = VidpScrollRegion[0];
}
}
}
}
VOID VOID
NTAPI NTAPI
VidBufferToScreenBlt( VidBufferToScreenBlt(
@ -347,14 +471,16 @@ VidBitBlt(
PBITMAPINFOHEADER BitmapInfoHeader; PBITMAPINFOHEADER BitmapInfoHeader;
LONG Delta; LONG Delta;
PUCHAR BitmapOffset; PUCHAR BitmapOffset;
ULONG PaletteCount;
/* Get the Bitmap Header */ /* Get the Bitmap Header */
BitmapInfoHeader = (PBITMAPINFOHEADER)Buffer; BitmapInfoHeader = (PBITMAPINFOHEADER)Buffer;
/* Initialize the palette */ /* Initialize the palette */
PaletteCount = BitmapInfoHeader->biClrUsed ?
BitmapInfoHeader->biClrUsed : BV_MAX_COLORS;
InitPaletteWithTable((PULONG)(Buffer + BitmapInfoHeader->biSize), InitPaletteWithTable((PULONG)(Buffer + BitmapInfoHeader->biSize),
(BitmapInfoHeader->biClrUsed) ? PaletteCount);
BitmapInfoHeader->biClrUsed : 16);
/* Make sure we can support this bitmap */ /* Make sure we can support this bitmap */
ASSERT((BitmapInfoHeader->biBitCount * BitmapInfoHeader->biPlanes) <= 4); ASSERT((BitmapInfoHeader->biBitCount * BitmapInfoHeader->biPlanes) <= 4);
@ -366,7 +492,7 @@ VidBitBlt(
Delta = (BitmapInfoHeader->biBitCount * BitmapInfoHeader->biWidth) + 31; Delta = (BitmapInfoHeader->biBitCount * BitmapInfoHeader->biWidth) + 31;
Delta >>= 3; Delta >>= 3;
Delta &= ~3; Delta &= ~3;
BitmapOffset = Buffer + sizeof(BITMAPINFOHEADER) + 16 * sizeof(ULONG); BitmapOffset = Buffer + sizeof(BITMAPINFOHEADER) + PaletteCount * sizeof(ULONG);
/* Check the compression of the bitmap */ /* Check the compression of the bitmap */
if (BitmapInfoHeader->biCompression == BI_RLE4) if (BitmapInfoHeader->biCompression == BI_RLE4)

View file

@ -6,7 +6,7 @@
// Available from http://mirtchovski.com/p9/fonts/ // Available from http://mirtchovski.com/p9/fonts/
// FontData Array generated by bootvid_font_generator. // FontData Array generated by bootvid_font_generator.
// //
UCHAR FontData[256 * BOOTCHAR_HEIGHT] = UCHAR VidpFontData[256 * BOOTCHAR_HEIGHT] =
{ {
0x00, 0x00, 0x00, 0x00, 0xFE, 0x82, 0x82, 0x82, 0x82, 0x82, 0xFE, 0x00, 0x00, // 0 0x00, 0x00, 0x00, 0x00, 0xFE, 0x82, 0x82, 0x82, 0x82, 0x82, 0xFE, 0x00, 0x00, // 0
0x00, 0x00, 0x00, 0x00, 0xFE, 0x82, 0x82, 0x82, 0x82, 0x82, 0xFE, 0x00, 0x00, // 13 0x00, 0x00, 0x00, 0x00, 0xFE, 0x82, 0x82, 0x82, 0x82, 0x82, 0xFE, 0x00, 0x00, // 13

View file

@ -4,7 +4,8 @@
static BOOLEAN static BOOLEAN
NTAPI NTAPI
VgaInterpretCmdStream(IN PUSHORT CmdStream) VgaInterpretCmdStream(
_In_ PUSHORT CmdStream)
{ {
USHORT Cmd; USHORT Cmd;
UCHAR Major, Minor; UCHAR Major, Minor;
@ -358,7 +359,8 @@ VgaIsPresent(VOID)
*/ */
BOOLEAN BOOLEAN
NTAPI NTAPI
VidInitialize(IN BOOLEAN SetMode) VidInitialize(
_In_ BOOLEAN SetMode)
{ {
ULONG_PTR Context = 0; ULONG_PTR Context = 0;
PHYSICAL_ADDRESS TranslatedAddress; PHYSICAL_ADDRESS TranslatedAddress;
@ -464,7 +466,8 @@ VidInitialize(IN BOOLEAN SetMode)
*/ */
VOID VOID
NTAPI NTAPI
VidResetDisplay(IN BOOLEAN HalReset) VidResetDisplay(
_In_ BOOLEAN HalReset)
{ {
/* Clear the current position */ /* Clear the current position */
VidpCurrentX = 0; VidpCurrentX = 0;
@ -485,5 +488,5 @@ VidResetDisplay(IN BOOLEAN HalReset)
/* Re-initialize the palette and fill the screen black */ /* Re-initialize the palette and fill the screen black */
InitializePalette(); InitializePalette();
VidSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, 0); VidSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLACK);
} }

View file

@ -19,6 +19,15 @@ extern UCHAR PixelMask[8];
#define __outpw(Port, Value) \ #define __outpw(Port, Value) \
WRITE_PORT_USHORT((PUSHORT)(VgaRegisterBase + (Port)), (USHORT)(Value)) WRITE_PORT_USHORT((PUSHORT)(VgaRegisterBase + (Port)), (USHORT)(Value))
VOID
NTAPI
InitPaletteWithTable(
_In_ PULONG Table,
_In_ ULONG Count);
VOID
PrepareForSetPixel(VOID);
FORCEINLINE FORCEINLINE
VOID VOID
SetPixel( SetPixel(
@ -37,3 +46,24 @@ SetPixel(
/* Read the current pixel value and add our color */ /* Read the current pixel value and add our color */
WRITE_REGISTER_UCHAR(PixelPosition, READ_REGISTER_UCHAR(PixelPosition) & Color); WRITE_REGISTER_UCHAR(PixelPosition, READ_REGISTER_UCHAR(PixelPosition) & Color);
} }
VOID
NTAPI
PreserveRow(
_In_ ULONG CurrentTop,
_In_ ULONG TopDelta,
_In_ BOOLEAN Restore);
VOID
NTAPI
DoScroll(
_In_ ULONG Scroll);
VOID
NTAPI
DisplayCharacter(
_In_ CHAR Character,
_In_ ULONG Left,
_In_ ULONG Top,
_In_ ULONG TextColor,
_In_ ULONG BackColor);

View file

@ -57,13 +57,13 @@ static ULONG lookup[16] =
ULONG_PTR VgaRegisterBase = 0; ULONG_PTR VgaRegisterBase = 0;
ULONG_PTR VgaBase = 0; ULONG_PTR VgaBase = 0;
static BOOLEAN ClearRow = FALSE;
/* PRIVATE FUNCTIONS *********************************************************/ /* PRIVATE FUNCTIONS *********************************************************/
static VOID static VOID
NTAPI NTAPI
ReadWriteMode(IN UCHAR Mode) ReadWriteMode(
_In_ UCHAR Mode)
{ {
UCHAR Value; UCHAR Value;
@ -98,14 +98,6 @@ do { \
WRITE_REGISTER_UCHAR((_PixelPtr), (UCHAR)(_TextColor)); \ WRITE_REGISTER_UCHAR((_PixelPtr), (UCHAR)(_TextColor)); \
} while (0); } 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
VOID VOID
NTAPI NTAPI
DisplayCharacter( DisplayCharacter(
@ -156,7 +148,7 @@ DisplayCharacter(
} }
/* Check if the background color is transparent */ /* Check if the background color is transparent */
if (BackColor >= 16) if (BackColor >= BV_COLOR_NONE)
{ {
/* We are done */ /* We are done */
return; return;
@ -199,18 +191,17 @@ DisplayCharacter(
static VOID static VOID
NTAPI NTAPI
SetPaletteEntryRGB(IN ULONG Id, SetPaletteEntryRGB(
IN ULONG Rgb) _In_ ULONG Id,
_In_ RGBQUAD Rgb)
{ {
PCHAR Colors = (PCHAR)&Rgb;
/* Set the palette index */ /* Set the palette index */
__outpb(VGA_BASE_IO_PORT + DAC_ADDRESS_WRITE_PORT, (UCHAR)Id); __outpb(VGA_BASE_IO_PORT + DAC_ADDRESS_WRITE_PORT, (UCHAR)Id);
/* Set RGB colors */ /* Set RGB colors */
__outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, Colors[2] >> 2); __outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, GetRValue(Rgb) >> 2);
__outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, Colors[1] >> 2); __outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, GetGValue(Rgb) >> 2);
__outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, Colors[0] >> 2); __outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, GetBValue(Rgb) >> 2);
} }
VOID VOID
@ -222,57 +213,16 @@ InitPaletteWithTable(
ULONG i; ULONG i;
PULONG Entry = Table; PULONG Entry = Table;
/* Loop every entry */
for (i = 0; i < Count; i++, Entry++) for (i = 0; i < Count; i++, Entry++)
{ {
/* Set the entry */
SetPaletteEntryRGB(i, *Entry); SetPaletteEntryRGB(i, *Entry);
} }
} }
static VOID
NTAPI
SetPaletteEntry(IN ULONG Id,
IN ULONG PaletteEntry)
{
/* Set the palette index */
__outpb(VGA_BASE_IO_PORT + DAC_ADDRESS_WRITE_PORT, (UCHAR)Id);
/* Set RGB colors */
__outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, PaletteEntry & 0xFF);
__outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, (PaletteEntry >>= 8) & 0xFF);
__outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, (PaletteEntry >> 8) & 0xFF);
}
VOID VOID
NTAPI NTAPI
InitializePalette(VOID) DoScroll(
{ _In_ ULONG Scroll)
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; ULONG Top, RowSize;
PUCHAR OldPosition, NewPosition; PUCHAR OldPosition, NewPosition;
@ -309,11 +259,12 @@ VgaScroll(IN ULONG Scroll)
} }
} }
static VOID VOID
NTAPI NTAPI
PreserveRow(IN ULONG CurrentTop, PreserveRow(
IN ULONG TopDelta, _In_ ULONG CurrentTop,
IN BOOLEAN Restore) _In_ ULONG TopDelta,
_In_ BOOLEAN Restore)
{ {
PUCHAR Position1, Position2; PUCHAR Position1, Position2;
ULONG Count; ULONG Count;
@ -360,21 +311,6 @@ PreserveRow(IN ULONG CurrentTop,
/* PUBLIC FUNCTIONS **********************************************************/ /* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
ULONG
NTAPI
VidSetTextColor(IN ULONG Color)
{
ULONG OldColor;
/* Save the old color and set the new one */
OldColor = VidpTextColor;
VidpTextColor = Color;
return OldColor;
}
/* /*
* @implemented * @implemented
*/ */
@ -392,94 +328,13 @@ VidCleanUp(VOID)
*/ */
VOID VOID
NTAPI NTAPI
VidDisplayString(IN PUCHAR String) VidScreenToBufferBlt(
{ _Out_ PUCHAR Buffer,
ULONG TopDelta = BOOTCHAR_HEIGHT + 1; _In_ ULONG Left,
_In_ ULONG Top,
/* Start looping the string */ _In_ ULONG Width,
for (; *String; ++String) _In_ ULONG Height,
{ _In_ ULONG Delta)
/* Treat new-line separately */
if (*String == '\n')
{
/* Modify Y position */
VidpCurrentY += TopDelta;
if (VidpCurrentY + TopDelta - 1 > VidpScrollRegion[3])
{
/* Scroll the view and clear the current row */
VgaScroll(TopDelta);
VidpCurrentY -= TopDelta;
PreserveRow(VidpCurrentY, TopDelta, TRUE);
}
else
{
/* Preserve the current row */
PreserveRow(VidpCurrentY, TopDelta, FALSE);
}
/* Update current X */
VidpCurrentX = VidpScrollRegion[0];
/* No need to clear this row */
ClearRow = FALSE;
}
else if (*String == '\r')
{
/* Update current X */
VidpCurrentX = VidpScrollRegion[0];
/* If a new-line does not follow we will clear the current row */
if (String[1] != '\n') ClearRow = TRUE;
}
else
{
/* Clear the current row if we had a return-carriage without a new-line */
if (ClearRow)
{
PreserveRow(VidpCurrentY, TopDelta, TRUE);
ClearRow = FALSE;
}
/* Display this character */
DisplayCharacter(*String, VidpCurrentX, VidpCurrentY, VidpTextColor, 16);
VidpCurrentX += 8;
/* Check if we should scroll */
if (VidpCurrentX + 7 > VidpScrollRegion[2])
{
/* Update Y position and check if we should scroll it */
VidpCurrentY += TopDelta;
if (VidpCurrentY + TopDelta - 1 > VidpScrollRegion[3])
{
/* Scroll the view and clear the current row */
VgaScroll(TopDelta);
VidpCurrentY -= TopDelta;
PreserveRow(VidpCurrentY, TopDelta, TRUE);
}
else
{
/* Preserve the current row */
PreserveRow(VidpCurrentY, TopDelta, FALSE);
}
/* Update current X */
VidpCurrentX = VidpScrollRegion[0];
}
}
}
}
/*
* @implemented
*/
VOID
NTAPI
VidScreenToBufferBlt(OUT PUCHAR Buffer,
IN ULONG Left,
IN ULONG Top,
IN ULONG Width,
IN ULONG Height,
IN ULONG Delta)
{ {
ULONG Plane; ULONG Plane;
ULONG XDistance; ULONG XDistance;
@ -573,11 +428,12 @@ VidScreenToBufferBlt(OUT PUCHAR Buffer,
*/ */
VOID VOID
NTAPI NTAPI
VidSolidColorFill(IN ULONG Left, VidSolidColorFill(
IN ULONG Top, _In_ ULONG Left,
IN ULONG Right, _In_ ULONG Top,
IN ULONG Bottom, _In_ ULONG Right,
IN UCHAR Color) _In_ ULONG Bottom,
_In_ UCHAR Color)
{ {
ULONG rMask, lMask; ULONG rMask, lMask;
ULONG LeftOffset, RightOffset, Distance; ULONG LeftOffset, RightOffset, Distance;

View file

@ -41,35 +41,7 @@ typedef struct tagBITMAPINFOHEADER
#define BI_RGB 0 #define BI_RGB 0
#define BI_RLE4 2 #define BI_RLE4 2
typedef struct _PALETTE_ENTRY typedef ULONG RGBQUAD;
{
UCHAR Red;
UCHAR Green;
UCHAR Blue;
} PALETTE_ENTRY, *PPALETTE_ENTRY;
VOID
NTAPI
InitializePalette(VOID);
VOID
NTAPI
DisplayCharacter(
_In_ CHAR Character,
_In_ ULONG Left,
_In_ ULONG Top,
_In_ ULONG TextColor,
_In_ ULONG BackColor
);
VOID
PrepareForSetPixel(VOID);
VOID
NTAPI
InitPaletteWithTable(
_In_ PULONG Table,
_In_ ULONG Count);
/* /*
* Globals * Globals
@ -78,6 +50,23 @@ extern UCHAR VidpTextColor;
extern ULONG VidpCurrentX; extern ULONG VidpCurrentX;
extern ULONG VidpCurrentY; extern ULONG VidpCurrentY;
extern ULONG VidpScrollRegion[4]; extern ULONG VidpScrollRegion[4];
extern UCHAR FontData[256 * BOOTCHAR_HEIGHT]; extern UCHAR VidpFontData[256 * BOOTCHAR_HEIGHT];
extern const RGBQUAD VidpDefaultPalette[BV_MAX_COLORS];
#define RGB(r, g, b) ((RGBQUAD)(((UCHAR)(b) | ((USHORT)((UCHAR)(g))<<8)) | (((ULONG)(UCHAR)(r))<<16)))
#define GetRValue(quad) ((UCHAR)(((quad)>>16) & 0xFF))
#define GetGValue(quad) ((UCHAR)(((quad)>>8) & 0xFF))
#define GetBValue(quad) ((UCHAR)((quad) & 0xFF))
#define InitializePalette() InitPaletteWithTable((PULONG)VidpDefaultPalette, BV_MAX_COLORS)
#ifdef CHAR_GEN_UPSIDE_DOWN
# define GetFontPtr(_Char) &VidpFontData[_Char * BOOTCHAR_HEIGHT] + BOOTCHAR_HEIGHT - 1;
# define FONT_PTR_DELTA (-1)
#else
# define GetFontPtr(_Char) &VidpFontData[_Char * BOOTCHAR_HEIGHT];
# define FONT_PTR_DELTA (1)
#endif
#endif /* _BOOTVID_PCH_ */ #endif /* _BOOTVID_PCH_ */

View file

@ -244,7 +244,7 @@ HalHandleNMI(IN PVOID NmiInfo)
SystemControl.Bits = __inbyte(SYSTEM_CONTROL_PORT_B); SystemControl.Bits = __inbyte(SYSTEM_CONTROL_PORT_B);
// //
// Switch to boot vieo // Switch to boot video
// //
if (InbvIsBootDriverInstalled()) if (InbvIsBootDriverInstalled())
{ {
@ -257,13 +257,13 @@ HalHandleNMI(IN PVOID NmiInfo)
// //
// Fill the screen // Fill the screen
// //
InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, 1); InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_RED);
InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1); InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
// //
// Enable text // Enable text
// //
InbvSetTextColor(15); InbvSetTextColor(BV_COLOR_WHITE);
InbvInstallDisplayStringFilter(NULL); InbvInstallDisplayStringFilter(NULL);
InbvEnableDisplayString(TRUE); InbvEnableDisplayString(TRUE);
} }

View file

@ -779,7 +779,7 @@ InbvUpdateProgressBar(IN ULONG Progress)
ProgressBarTop, ProgressBarTop,
ProgressBarLeft + FillCount, ProgressBarLeft + FillCount,
ProgressBarTop + 12, ProgressBarTop + 12,
15); BV_COLOR_WHITE);
/* Release the lock */ /* Release the lock */
InbvReleaseLock(); InbvReleaseLock();
@ -827,7 +827,7 @@ InbvBitBlt(IN PUCHAR Buffer,
VOID VOID
NTAPI NTAPI
InbvScreenToBufferBlt(IN PUCHAR Buffer, InbvScreenToBufferBlt(OUT PUCHAR Buffer,
IN ULONG X, IN ULONG X,
IN ULONG Y, IN ULONG Y,
IN ULONG Width, IN ULONG Width,
@ -1021,7 +1021,7 @@ InbvRotationThread(
if (Index >= 3) if (Index >= 3)
{ {
/* Fill previous bar position */ /* Fill previous bar position */
VidSolidColorFill(X + ((Index - 3) * 8), Y, (X + ((Index - 3) * 8)) + 8 - 1, Y + 9 - 1, 0); VidSolidColorFill(X + ((Index - 3) * 8), Y, (X + ((Index - 3) * 8)) + 8 - 1, Y + 9 - 1, BV_COLOR_BLACK);
} }
if (Index < Total - 1) if (Index < Total - 1)
{ {
@ -1120,9 +1120,9 @@ DisplayBootBitmap(IN BOOLEAN TextMode)
if (SharedUserData->NtProductType == NtProductWinNt) if (SharedUserData->NtProductType == NtProductWinNt)
{ {
/* Workstation; set colors */ /* Workstation; set colors */
InbvSetTextColor(15); InbvSetTextColor(BV_COLOR_WHITE);
InbvSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, 7); InbvSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_DARK_GRAY);
InbvSolidColorFill(0, VID_FOOTER_BG_TOP, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, 1); InbvSolidColorFill(0, VID_FOOTER_BG_TOP, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_RED);
/* Get resources */ /* Get resources */
Header = InbvGetResourceAddress(IDB_WKSTA_HEADER); Header = InbvGetResourceAddress(IDB_WKSTA_HEADER);
@ -1131,9 +1131,9 @@ DisplayBootBitmap(IN BOOLEAN TextMode)
else else
{ {
/* Server; set colors */ /* Server; set colors */
InbvSetTextColor(14); InbvSetTextColor(BV_COLOR_LIGHT_CYAN);
InbvSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, 6); InbvSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_CYAN);
InbvSolidColorFill(0, VID_FOOTER_BG_TOP, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, 1); InbvSolidColorFill(0, VID_FOOTER_BG_TOP, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_RED);
/* Get resources */ /* Get resources */
Header = InbvGetResourceAddress(IDB_SERVER_HEADER); Header = InbvGetResourceAddress(IDB_SERVER_HEADER);
@ -1246,7 +1246,7 @@ DisplayBootBitmap(IN BOOLEAN TextMode)
InbvScreenToBufferBlt(Buffer, VID_SKU_SAVE_AREA_LEFT, InbvScreenToBufferBlt(Buffer, VID_SKU_SAVE_AREA_LEFT,
VID_SKU_SAVE_AREA_TOP, 7, 7, 8); VID_SKU_SAVE_AREA_TOP, 7, 7, 8);
InbvSolidColorFill(VID_SKU_AREA_LEFT, VID_SKU_AREA_TOP, InbvSolidColorFill(VID_SKU_AREA_LEFT, VID_SKU_AREA_TOP,
VID_SKU_AREA_RIGHT, VID_SKU_AREA_BOTTOM, 0); VID_SKU_AREA_RIGHT, VID_SKU_AREA_BOTTOM, BV_COLOR_BLACK);
InbvBufferToScreenBlt(Buffer, VID_SKU_SAVE_AREA_LEFT, InbvBufferToScreenBlt(Buffer, VID_SKU_SAVE_AREA_LEFT,
VID_SKU_SAVE_AREA_TOP, 7, 7, 8); VID_SKU_SAVE_AREA_TOP, 7, 7, 8);
@ -1390,7 +1390,7 @@ FinalizeBootLogo(VOID)
if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED) if (InbvGetDisplayState() == INBV_DISPLAY_STATE_OWNED)
{ {
/* Clear the screen */ /* Clear the screen */
VidSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, 0); VidSolidColorFill(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1, BV_COLOR_BLACK);
} }
/* Reset progress bar and lock */ /* Reset progress bar and lock */

View file

@ -418,8 +418,8 @@ KdpScreenAcquire(VOID)
/* Acquire ownership and reset the display */ /* Acquire ownership and reset the display */
InbvAcquireDisplayOwnership(); InbvAcquireDisplayOwnership();
InbvResetDisplay(); InbvResetDisplay();
InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, 0); InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLACK);
InbvSetTextColor(15); InbvSetTextColor(BV_COLOR_WHITE);
InbvInstallDisplayStringFilter(NULL); InbvInstallDisplayStringFilter(NULL);
InbvEnableDisplayString(TRUE); InbvEnableDisplayString(TRUE);
InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1); InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);

View file

@ -626,8 +626,8 @@ KiDisplayBlueScreen(IN ULONG MessageId,
InbvResetDisplay(); InbvResetDisplay();
/* Display blue screen */ /* Display blue screen */
InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, 4); InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLUE);
InbvSetTextColor(15); InbvSetTextColor(BV_COLOR_WHITE);
InbvInstallDisplayStringFilter(NULL); InbvInstallDisplayStringFilter(NULL);
InbvEnableDisplayString(TRUE); InbvEnableDisplayString(TRUE);
InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1); InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);

View file

@ -162,7 +162,7 @@ PopShutdownHandler(VOID)
/* Yes we do, cleanup for shutdown screen */ /* Yes we do, cleanup for shutdown screen */
if (!InbvCheckDisplayOwnership()) InbvAcquireDisplayOwnership(); if (!InbvCheckDisplayOwnership()) InbvAcquireDisplayOwnership();
InbvResetDisplay(); InbvResetDisplay();
InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, 0); InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLACK);
InbvEnableDisplayString(TRUE); InbvEnableDisplayString(TRUE);
InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1); InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);

View file

@ -14,29 +14,34 @@
BOOLEAN BOOLEAN
NTAPI NTAPI
VidInitialize(IN BOOLEAN SetMode); VidInitialize(
_In_ BOOLEAN SetMode);
VOID VOID
NTAPI NTAPI
VidResetDisplay(IN BOOLEAN HalReset); VidResetDisplay(
_In_ BOOLEAN HalReset);
ULONG ULONG
NTAPI NTAPI
VidSetTextColor(IN ULONG Color); VidSetTextColor(
_In_ ULONG Color);
VOID VOID
NTAPI NTAPI
VidDisplayStringXY(IN PUCHAR String, VidDisplayStringXY(
IN ULONG Left, _In_ PUCHAR String,
IN ULONG Top, _In_ ULONG Left,
IN BOOLEAN Transparent); _In_ ULONG Top,
_In_ BOOLEAN Transparent);
VOID VOID
NTAPI NTAPI
VidSetScrollRegion(IN ULONG Left, VidSetScrollRegion(
IN ULONG Top, _In_ ULONG Left,
IN ULONG Right, _In_ ULONG Top,
IN ULONG Bottom); _In_ ULONG Right,
_In_ ULONG Bottom);
VOID VOID
NTAPI NTAPI
@ -44,38 +49,43 @@ VidCleanUp(VOID);
VOID VOID
NTAPI NTAPI
VidBufferToScreenBlt(IN PUCHAR Buffer, VidBufferToScreenBlt(
IN ULONG Left, _In_ PUCHAR Buffer,
IN ULONG Top, _In_ ULONG Left,
IN ULONG Width, _In_ ULONG Top,
IN ULONG Height, _In_ ULONG Width,
IN ULONG Delta); _In_ ULONG Height,
_In_ ULONG Delta);
VOID VOID
NTAPI NTAPI
VidDisplayString(IN PUCHAR String); VidDisplayString(
_In_ PUCHAR String);
VOID VOID
NTAPI NTAPI
VidBitBlt(IN PUCHAR Buffer, VidBitBlt(
IN ULONG Left, _In_ PUCHAR Buffer,
IN ULONG Top); _In_ ULONG Left,
_In_ ULONG Top);
VOID VOID
NTAPI NTAPI
VidScreenToBufferBlt(OUT PUCHAR Buffer, VidScreenToBufferBlt(
IN ULONG Left, _Out_ PUCHAR Buffer,
IN ULONG Top, _In_ ULONG Left,
IN ULONG Width, _In_ ULONG Top,
IN ULONG Height, _In_ ULONG Width,
IN ULONG Delta); _In_ ULONG Height,
_In_ ULONG Delta);
VOID VOID
NTAPI NTAPI
VidSolidColorFill(IN ULONG Left, VidSolidColorFill(
IN ULONG Top, _In_ ULONG Left,
IN ULONG Right, _In_ ULONG Top,
IN ULONG Bottom, _In_ ULONG Right,
IN UCHAR Color); _In_ ULONG Bottom,
_In_ UCHAR Color);
#endif // _BOOTVID_ #endif // _BOOTVID_

View file

@ -10,3 +10,23 @@
/* For default VGA */ /* For default VGA */
#define SCREEN_WIDTH 640 #define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480 #define SCREEN_HEIGHT 480
/* Boot video default color palette constants */
#define BV_COLOR_BLACK 0
#define BV_COLOR_RED 1
#define BV_COLOR_GREEN 2
#define BV_COLOR_BROWN 3
#define BV_COLOR_BLUE 4
#define BV_COLOR_MAGENTA 5
#define BV_COLOR_CYAN 6
#define BV_COLOR_DARK_GRAY 7
#define BV_COLOR_LIGHT_GRAY 8
#define BV_COLOR_LIGHT_RED 9
#define BV_COLOR_LIGHT_GREEN 10
#define BV_COLOR_YELLOW 11
#define BV_COLOR_LIGHT_BLUE 12
#define BV_COLOR_LIGHT_MAGENTA 13
#define BV_COLOR_LIGHT_CYAN 14
#define BV_COLOR_WHITE 15
#define BV_COLOR_NONE 16
#define BV_MAX_COLORS 16