Files
reactos/drivers/base/bootvid/common.c
Dmitry Borisov e2aa54321a [BOOTVID] Rename some function parameters
Delta       -> Stride
TopDelta -> Height
2026-04-21 15:08:17 -05:00

392 lines
10 KiB
C

/*
* PROJECT: ReactOS Boot Video Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Platform-independent common helpers and defines
* COPYRIGHT: Copyright 2010 Gregor Schneider <gregor.schneider@reactos.org>
* Copyright 2011 Rafal Harabien <rafalh@reactos.org>
* Copyright 2020 Stanislav Motylkov <x86corez@gmail.com>
*/
#include "precomp.h"
/* GLOBALS ********************************************************************/
/*
* 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 */
};
/* PRIVATE FUNCTIONS **********************************************************/
static VOID
BitBlt(
_In_ ULONG Left,
_In_ ULONG Top,
_In_ ULONG Width,
_In_ ULONG Height,
_In_reads_bytes_(Height * Stride) PUCHAR Buffer,
_In_ ULONG BitsPerPixel,
_In_ ULONG Stride)
{
ULONG X, Y, Pixel;
UCHAR Colors;
PUCHAR InputBuffer;
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. Stride: %lu\n",
Width,
Height,
Left,
Top,
BitsPerPixel,
Buffer,
Stride);
return;
}
PrepareForSetPixel();
/* 4bpp blitting */
for (Y = Top; Y < Bottom; ++Y)
{
InputBuffer = Buffer;
for (X = Left, Pixel = 0;
X < Right;
++X, ++Pixel)
{
if (Pixel % 2 == 0)
{
/* Extract colors at every two pixels */
Colors = *InputBuffer++;
SetPixel(X, Y, Colors >> 4);
}
else
{
SetPixel(X, Y, Colors & 0x0F);
}
}
Buffer += Stride;
}
}
static VOID
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;
PrepareForSetPixel();
/* 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 */
for (i = (RleValue - 2) / 2 + 1; i > 0; --i)
{
/* Set the pixels */
SetPixel(x, YDelta, (UCHAR)Color);
x++;
SetPixel(x, YDelta, (UCHAR)Color2);
x++;
/* Decrease pixel value */
RleValue -= 2;
}
}
/* 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 */
for (j = (RleValue - 2) / 2 + 1; j > 0; --j)
{
/* 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;
}
}
/* 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 ***********************************************************/
VOID
NTAPI
VidBufferToScreenBlt(
_In_reads_bytes_(Height * Stride) PUCHAR Buffer,
_In_ ULONG Left,
_In_ ULONG Top,
_In_ ULONG Width,
_In_ ULONG Height,
_In_ ULONG Stride)
{
/* Make sure we have a width and height */
if (!Width || !Height)
return;
/* Call the helper function */
BitBlt(Left, Top, Width, Height, Buffer, 4, Stride);
}
VOID
NTAPI
VidBitBlt(
_In_ PUCHAR Buffer,
_In_ ULONG Left,
_In_ ULONG Top)
{
PBITMAPINFOHEADER BitmapInfoHeader;
LONG Stride;
PUCHAR BitmapOffset;
ULONG PaletteCount;
/* Get the Bitmap Header */
BitmapInfoHeader = (PBITMAPINFOHEADER)Buffer;
/* Initialize the palette */
PaletteCount = BitmapInfoHeader->biClrUsed ?
BitmapInfoHeader->biClrUsed : BV_MAX_COLORS;
InitPaletteWithTable((PULONG)(Buffer + BitmapInfoHeader->biSize),
PaletteCount);
/* Make sure we can support this bitmap */
ASSERT((BitmapInfoHeader->biBitCount * BitmapInfoHeader->biPlanes) <= 4);
/*
* Calculate the stride and align it on 32-bytes, then calculate
* the actual start of the bitmap data.
*/
Stride = (BitmapInfoHeader->biBitCount * BitmapInfoHeader->biWidth) + 31;
Stride >>= 3;
Stride &= ~3;
BitmapOffset = Buffer + sizeof(BITMAPINFOHEADER) + PaletteCount * 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) * Stride);
Stride *= -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,
Stride);
}
}
}