|
|
|
|
@@ -25,10 +25,9 @@ XTAPI
|
|
|
|
|
VOID
|
|
|
|
|
HL::FrameBuffer::ClearScreen(IN ULONG Color)
|
|
|
|
|
{
|
|
|
|
|
ULONG PositionX, PositionY;
|
|
|
|
|
ULONG BackgroundColor;
|
|
|
|
|
PCHAR CurrentLine;
|
|
|
|
|
PULONG Pixel;
|
|
|
|
|
ULONG BackgroundColor, PositionY;
|
|
|
|
|
PCHAR CurrentLine, TargetBuffer;
|
|
|
|
|
UCHAR FillByte;
|
|
|
|
|
|
|
|
|
|
/* Make sure frame buffer is already initialized */
|
|
|
|
|
if(FrameBufferData.Initialized == FALSE)
|
|
|
|
|
@@ -37,20 +36,29 @@ HL::FrameBuffer::ClearScreen(IN ULONG Color)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert background color and get pointer to frame buffer */
|
|
|
|
|
/* Convert background color */
|
|
|
|
|
BackgroundColor = GetRGBColor(Color);
|
|
|
|
|
CurrentLine = (PCHAR)FrameBufferData.Address;
|
|
|
|
|
|
|
|
|
|
/* Extract the lower byte for SetMemory */
|
|
|
|
|
FillByte = (UCHAR)(BackgroundColor & 0xFF);
|
|
|
|
|
|
|
|
|
|
/* Determine target buffer */
|
|
|
|
|
TargetBuffer = (ScreenShadowBuffer != NULLPTR) ? (PCHAR)ScreenShadowBuffer : (PCHAR)FrameBufferData.Address;
|
|
|
|
|
CurrentLine = TargetBuffer;
|
|
|
|
|
|
|
|
|
|
/* Fill the screen with the specified color */
|
|
|
|
|
for(PositionY = 0; PositionY < FrameBufferData.Height; PositionY++, CurrentLine += FrameBufferData.Pitch)
|
|
|
|
|
{
|
|
|
|
|
/* Fill the current line with the specified color */
|
|
|
|
|
Pixel = (PULONG)CurrentLine;
|
|
|
|
|
for(PositionX = 0; PositionX < FrameBufferData.Width; PositionX++)
|
|
|
|
|
{
|
|
|
|
|
/* Set the color of the pixel */
|
|
|
|
|
Pixel[PositionX] = BackgroundColor;
|
|
|
|
|
/* Fill the current scanline with the background color byte */
|
|
|
|
|
RTL::Memory::SetMemory(CurrentLine, FillByte, FrameBufferData.Width * FrameBufferData.BytesPerPixel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check if Shadow Buffer is active */
|
|
|
|
|
if(ScreenShadowBuffer != NULLPTR)
|
|
|
|
|
{
|
|
|
|
|
/* Flush changes to VRAM */
|
|
|
|
|
RTL::Memory::CopyMemory(FrameBufferData.Address, ScreenShadowBuffer,
|
|
|
|
|
FrameBufferData.Pitch * FrameBufferData.Height);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -68,7 +76,9 @@ XTCDECL
|
|
|
|
|
XTSTATUS
|
|
|
|
|
HL::FrameBuffer::DisplayCharacter(IN WCHAR Character)
|
|
|
|
|
{
|
|
|
|
|
ULONG CharacterX, CharacterY;
|
|
|
|
|
PSSFN_FONT_HEADER FbFont;
|
|
|
|
|
BOOLEAN VisibleCharacter;
|
|
|
|
|
|
|
|
|
|
/* Make sure frame buffer is already initialized */
|
|
|
|
|
if(FrameBufferData.Initialized == FALSE)
|
|
|
|
|
@@ -80,6 +90,9 @@ HL::FrameBuffer::DisplayCharacter(IN WCHAR Character)
|
|
|
|
|
/* Get font information */
|
|
|
|
|
FbFont = (PSSFN_FONT_HEADER)FrameBufferData.Font;
|
|
|
|
|
|
|
|
|
|
/* Assume invisible character */
|
|
|
|
|
VisibleCharacter = FALSE;
|
|
|
|
|
|
|
|
|
|
/* Handle special characters */
|
|
|
|
|
switch(Character)
|
|
|
|
|
{
|
|
|
|
|
@@ -98,8 +111,13 @@ HL::FrameBuffer::DisplayCharacter(IN WCHAR Character)
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* Draw the character */
|
|
|
|
|
DrawCharacter(ScrollRegionData.CursorX, ScrollRegionData.CursorY, ScrollRegionData.TextColor, Character);
|
|
|
|
|
/* Save cursor position */
|
|
|
|
|
CharacterX = ScrollRegionData.CursorX;
|
|
|
|
|
CharacterY = ScrollRegionData.CursorY;
|
|
|
|
|
|
|
|
|
|
/* Draw the character to RAM and mark it as visible */
|
|
|
|
|
DrawCharacter(CharacterX, CharacterY, ScrollRegionData.TextColor, Character);
|
|
|
|
|
VisibleCharacter = TRUE;
|
|
|
|
|
|
|
|
|
|
/* Advance cursor */
|
|
|
|
|
ScrollRegionData.CursorX += FbFont->Width;
|
|
|
|
|
@@ -107,6 +125,7 @@ HL::FrameBuffer::DisplayCharacter(IN WCHAR Character)
|
|
|
|
|
/* Check if cursor reached end of line */
|
|
|
|
|
if(ScrollRegionData.CursorX >= ScrollRegionData.Right)
|
|
|
|
|
{
|
|
|
|
|
/* Reset cursor to the left margin and advance to the next line */
|
|
|
|
|
ScrollRegionData.CursorX = ScrollRegionData.Left;
|
|
|
|
|
ScrollRegionData.CursorY += FbFont->Height;
|
|
|
|
|
}
|
|
|
|
|
@@ -120,6 +139,13 @@ HL::FrameBuffer::DisplayCharacter(IN WCHAR Character)
|
|
|
|
|
ScrollRegion();
|
|
|
|
|
ScrollRegionData.CursorY = ScrollRegionData.Bottom - FbFont->Height;
|
|
|
|
|
}
|
|
|
|
|
else if(VisibleCharacter == TRUE)
|
|
|
|
|
{
|
|
|
|
|
/* Flush visible character to VRAM */
|
|
|
|
|
UpdateScreenRegion(CharacterX, CharacterY,
|
|
|
|
|
CharacterX + FbFont->Width,
|
|
|
|
|
CharacterY + FbFont->Height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return success */
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
|
@@ -153,9 +179,8 @@ HL::FrameBuffer::DrawCharacter(IN ULONG PositionX,
|
|
|
|
|
{
|
|
|
|
|
UINT CurrentFragment, Glyph, GlyphLimit, Index, Line, Mapping;
|
|
|
|
|
PUCHAR Character, CharacterMapping, Fragment;
|
|
|
|
|
UINT_PTR GlyphPixel, Pixel;
|
|
|
|
|
ULONG FontColor, GlyphOffset, PixelOffset;
|
|
|
|
|
PSSFN_FONT_HEADER FbFont;
|
|
|
|
|
ULONG FontColor;
|
|
|
|
|
|
|
|
|
|
/* Make sure frame buffer is already initialized */
|
|
|
|
|
if(FrameBufferData.Initialized == FALSE)
|
|
|
|
|
@@ -192,7 +217,7 @@ HL::FrameBuffer::DrawCharacter(IN ULONG PositionX,
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* There's a glyph for this character, check if it matches */
|
|
|
|
|
/* There is a glyph for this character, check if it matches */
|
|
|
|
|
if(Index == WideCharacter)
|
|
|
|
|
{
|
|
|
|
|
/* Found the character, break loop */
|
|
|
|
|
@@ -213,8 +238,7 @@ HL::FrameBuffer::DrawCharacter(IN ULONG PositionX,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find the glyph position on the frame buffer and set font color */
|
|
|
|
|
GlyphPixel = (UINT_PTR)FrameBufferData.Address + PositionY * FrameBufferData.Pitch +
|
|
|
|
|
PositionX * FrameBufferData.BytesPerPixel;
|
|
|
|
|
GlyphOffset = (PositionY * FrameBufferData.Pitch) + (PositionX * FrameBufferData.BytesPerPixel);
|
|
|
|
|
FontColor = GetRGBColor(Color);
|
|
|
|
|
|
|
|
|
|
/* Check all kerning fragments */
|
|
|
|
|
@@ -243,7 +267,7 @@ HL::FrameBuffer::DrawCharacter(IN ULONG PositionX,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get initial glyph line */
|
|
|
|
|
GlyphPixel += (CharacterMapping[1] - Mapping) * FrameBufferData.Pitch;
|
|
|
|
|
GlyphOffset += (CharacterMapping[1] - Mapping) * FrameBufferData.Pitch;
|
|
|
|
|
Mapping = CharacterMapping[1];
|
|
|
|
|
|
|
|
|
|
/* Extract glyph data from fragments table and advance */
|
|
|
|
|
@@ -255,7 +279,8 @@ HL::FrameBuffer::DrawCharacter(IN ULONG PositionX,
|
|
|
|
|
CurrentFragment = 1;
|
|
|
|
|
while(GlyphLimit--)
|
|
|
|
|
{
|
|
|
|
|
Pixel = GlyphPixel;
|
|
|
|
|
/* Set the initial pixel offset for the current glyph fragment */
|
|
|
|
|
PixelOffset = GlyphOffset;
|
|
|
|
|
for(Line = 0; Line < Glyph; Line++)
|
|
|
|
|
{
|
|
|
|
|
/* Decode compressed offsets */
|
|
|
|
|
@@ -269,17 +294,26 @@ HL::FrameBuffer::DrawCharacter(IN ULONG PositionX,
|
|
|
|
|
/* Check if pixel should be drawn */
|
|
|
|
|
if(*Fragment & CurrentFragment)
|
|
|
|
|
{
|
|
|
|
|
/* Draw glyph pixel */
|
|
|
|
|
*((PULONG)Pixel) = FontColor;
|
|
|
|
|
/* Route the pixel draw operation to the active buffer */
|
|
|
|
|
if(ScreenShadowBuffer != NULLPTR)
|
|
|
|
|
{
|
|
|
|
|
/* Draw glyph pixel to Shadow Buffer */
|
|
|
|
|
*((PULONG)((PCHAR)ScreenShadowBuffer + PixelOffset)) = FontColor;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Draw glyph pixel directly to VRAM */
|
|
|
|
|
*((PULONG)((PCHAR)FrameBufferData.Address + PixelOffset)) = FontColor;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Advance pixel pointer */
|
|
|
|
|
Pixel += FrameBufferData.BytesPerPixel;
|
|
|
|
|
PixelOffset += FrameBufferData.BytesPerPixel;
|
|
|
|
|
CurrentFragment <<= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Advance to next line and increase mapping */
|
|
|
|
|
GlyphPixel += FrameBufferData.Pitch;
|
|
|
|
|
GlyphOffset += FrameBufferData.Pitch;
|
|
|
|
|
Mapping++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -310,7 +344,7 @@ HL::FrameBuffer::DrawPixel(IN ULONG PositionX,
|
|
|
|
|
IN ULONG PositionY,
|
|
|
|
|
IN ULONG Color)
|
|
|
|
|
{
|
|
|
|
|
PCHAR PixelAddress;
|
|
|
|
|
ULONG Offset;
|
|
|
|
|
|
|
|
|
|
/* Make sure frame buffer is already initialized */
|
|
|
|
|
if(FrameBufferData.Initialized == FALSE)
|
|
|
|
|
@@ -327,11 +361,67 @@ HL::FrameBuffer::DrawPixel(IN ULONG PositionX,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Calculate the address of the pixel in the frame buffer memory */
|
|
|
|
|
PixelAddress = (PCHAR)FrameBufferData.Address + (PositionY * FrameBufferData.Pitch) +
|
|
|
|
|
(PositionX * FrameBufferData.BytesPerPixel);
|
|
|
|
|
Offset = (PositionY * FrameBufferData.Pitch) + (PositionX * FrameBufferData.BytesPerPixel);
|
|
|
|
|
|
|
|
|
|
/* Set the color of the pixel by writing to the corresponding memory location */
|
|
|
|
|
*((PULONG)PixelAddress) = GetRGBColor(Color);
|
|
|
|
|
/* Route the pixel draw operation to the active buffer */
|
|
|
|
|
if(ScreenShadowBuffer != NULLPTR)
|
|
|
|
|
{
|
|
|
|
|
/* Set the color of the pixel by writing to the corresponding memory location (RAM) */
|
|
|
|
|
*((PULONG)((PCHAR)ScreenShadowBuffer + Offset)) = GetRGBColor(Color);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Set the color of the pixel by writing to the corresponding memory location (VRAM) */
|
|
|
|
|
*((PULONG)((PCHAR)FrameBufferData.Address + Offset)) = GetRGBColor(Color);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Enables the Shadow Buffer (Double Buffering) for high-performance rendering.
|
|
|
|
|
*
|
|
|
|
|
* @return This routine returns a status code.
|
|
|
|
|
*
|
|
|
|
|
* @since XT 1.0
|
|
|
|
|
*/
|
|
|
|
|
XTAPI
|
|
|
|
|
XTSTATUS
|
|
|
|
|
HL::FrameBuffer::EnableShadowBuffer(VOID)
|
|
|
|
|
{
|
|
|
|
|
ULONG FrameBufferSize;
|
|
|
|
|
XTSTATUS Status;
|
|
|
|
|
|
|
|
|
|
/* Check if the shadow buffer is already enabled */
|
|
|
|
|
if(ScreenShadowBuffer != NULLPTR)
|
|
|
|
|
{
|
|
|
|
|
/* Nothing to do, return success */
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make sure frame buffer is already initialized */
|
|
|
|
|
if(FrameBufferData.Initialized == FALSE)
|
|
|
|
|
{
|
|
|
|
|
/* Unable to operate on non-initialized frame buffer */
|
|
|
|
|
return STATUS_DEVICE_NOT_READY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Calculate the total size of the framebuffer */
|
|
|
|
|
FrameBufferSize = FrameBufferData.Pitch * FrameBufferData.Height;
|
|
|
|
|
|
|
|
|
|
/* Allocate non-paged memory for the shadow buffer */
|
|
|
|
|
Status = MM::Allocator::AllocatePool(NonPagedPool, FrameBufferSize,
|
|
|
|
|
&ScreenShadowBuffer, SIGNATURE32('F', 'B', 'U', 'F'));
|
|
|
|
|
if(Status != STATUS_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
/* Allocation failed, return status code */
|
|
|
|
|
ScreenShadowBuffer = NULLPTR;
|
|
|
|
|
return Status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Synchronize the newly allocated shadow buffer with the current on-screen contents */
|
|
|
|
|
RTL::Memory::CopyMemory(ScreenShadowBuffer, FrameBufferData.Address, FrameBufferSize);
|
|
|
|
|
|
|
|
|
|
/* Return success */
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -544,10 +634,9 @@ XTAPI
|
|
|
|
|
VOID
|
|
|
|
|
HL::FrameBuffer::ScrollRegion(VOID)
|
|
|
|
|
{
|
|
|
|
|
PCHAR Destination, Source;
|
|
|
|
|
PCHAR TargetBuffer, Destination, Source;
|
|
|
|
|
ULONG Line, PositionX, LineBytes;
|
|
|
|
|
PSSFN_FONT_HEADER FbFont;
|
|
|
|
|
ULONG Line, PositionX;
|
|
|
|
|
ULONG LineBytes;
|
|
|
|
|
PULONG Pixel;
|
|
|
|
|
|
|
|
|
|
/* Make sure frame buffer is already initialized */
|
|
|
|
|
@@ -557,37 +646,132 @@ HL::FrameBuffer::ScrollRegion(VOID)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get font information */
|
|
|
|
|
/* Retrieve font metrics and calculate line properties for the scroll operation */
|
|
|
|
|
FbFont = (PSSFN_FONT_HEADER)FrameBufferData.Font;
|
|
|
|
|
|
|
|
|
|
/* Calculate bytes per line in the scroll region */
|
|
|
|
|
LineBytes = (ScrollRegionData.Right - ScrollRegionData.Left) * FrameBufferData.BytesPerPixel;
|
|
|
|
|
TargetBuffer = (ScreenShadowBuffer != NULLPTR) ? (PCHAR)ScreenShadowBuffer : (PCHAR)FrameBufferData.Address;
|
|
|
|
|
|
|
|
|
|
/* Scroll up each scan line in the scroll region */
|
|
|
|
|
for(Line = ScrollRegionData.Top; Line < ScrollRegionData.Bottom - FbFont->Height; Line++)
|
|
|
|
|
/* Process every line in the scroll region */
|
|
|
|
|
for(Line = ScrollRegionData.Top; Line < ScrollRegionData.Bottom; Line++)
|
|
|
|
|
{
|
|
|
|
|
Destination = (PCHAR)FrameBufferData.Address + Line * FrameBufferData.Pitch +
|
|
|
|
|
ScrollRegionData.Left * FrameBufferData.BytesPerPixel;
|
|
|
|
|
/* Calculate destination address for the current line */
|
|
|
|
|
Destination = TargetBuffer + (Line * FrameBufferData.Pitch) +
|
|
|
|
|
(ScrollRegionData.Left * FrameBufferData.BytesPerPixel);
|
|
|
|
|
|
|
|
|
|
/* The source is one full text line (FbFont->Height) below the destination */
|
|
|
|
|
Source = (PCHAR)FrameBufferData.Address + (Line + FbFont->Height) * FrameBufferData.Pitch +
|
|
|
|
|
ScrollRegionData.Left * FrameBufferData.BytesPerPixel;
|
|
|
|
|
|
|
|
|
|
/* Move each scan line in the scroll region up */
|
|
|
|
|
RTL::Memory::MoveMemory(Destination, Source, LineBytes);
|
|
|
|
|
/* Check if the current line needs to be copied from below or cleared */
|
|
|
|
|
if(Line < ScrollRegionData.Bottom - FbFont->Height)
|
|
|
|
|
{
|
|
|
|
|
/* Copy the line from below */
|
|
|
|
|
Source = Destination + (FbFont->Height * FrameBufferData.Pitch);
|
|
|
|
|
RTL::Memory::CopyMemory(Destination, Source, LineBytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clear the last text line */
|
|
|
|
|
for(Line = ScrollRegionData.Bottom - FbFont->Height; Line < ScrollRegionData.Bottom; Line++)
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Get pointer to the start of the scan line to clear */
|
|
|
|
|
Pixel = (PULONG)((PCHAR)FrameBufferData.Address + Line * FrameBufferData.Pitch +
|
|
|
|
|
ScrollRegionData.Left * FrameBufferData.BytesPerPixel);
|
|
|
|
|
|
|
|
|
|
/* Clear each pixel in the scan line with the background color */
|
|
|
|
|
/* Fill the bottom line(s) with the background color */
|
|
|
|
|
Pixel = (PULONG)Destination;
|
|
|
|
|
for(PositionX = 0; PositionX < (ScrollRegionData.Right - ScrollRegionData.Left); PositionX++)
|
|
|
|
|
{
|
|
|
|
|
/* Overwrite the pixel with the background color */
|
|
|
|
|
Pixel[PositionX] = ScrollRegionData.BackgroundColor;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Flush changes to VRAM if Shadow Buffer was used */
|
|
|
|
|
if(ScreenShadowBuffer != NULLPTR)
|
|
|
|
|
{
|
|
|
|
|
/* Flush the updated scroll region to VRAM */
|
|
|
|
|
UpdateScreenRegion(ScrollRegionData.Left,
|
|
|
|
|
ScrollRegionData.Top,
|
|
|
|
|
ScrollRegionData.Right,
|
|
|
|
|
ScrollRegionData.Bottom);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Flushes the current content of the Shadow Buffer to the visible FrameBuffer (VRAM).
|
|
|
|
|
*
|
|
|
|
|
* @return This routine does not return any value.
|
|
|
|
|
*
|
|
|
|
|
* @since XT 1.0
|
|
|
|
|
*/
|
|
|
|
|
XTAPI
|
|
|
|
|
VOID
|
|
|
|
|
HL::FrameBuffer::UpdateScreen(VOID)
|
|
|
|
|
{
|
|
|
|
|
/* Make sure framebuffer is already initialized and shadow buffer is ready */
|
|
|
|
|
if(FrameBufferData.Initialized == FALSE || ScreenShadowBuffer == NULLPTR)
|
|
|
|
|
{
|
|
|
|
|
/* Unable to operate on non-initialized frame buffer */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Flush RAM to VRAM */
|
|
|
|
|
RTL::Memory::CopyMemory(FrameBufferData.Address,
|
|
|
|
|
ScreenShadowBuffer,
|
|
|
|
|
FrameBufferData.Pitch * FrameBufferData.Height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Flushes a specific rectangular region from the Shadow Buffer to the visible FrameBuffer (VRAM).
|
|
|
|
|
*
|
|
|
|
|
* @param Left
|
|
|
|
|
* Supplies the left pixel coordinate of the region to update.
|
|
|
|
|
*
|
|
|
|
|
* @param Top
|
|
|
|
|
* Supplies the top pixel coordinate of the region to update.
|
|
|
|
|
*
|
|
|
|
|
* @param Right
|
|
|
|
|
* Supplies the right pixel coordinate of the region to update.
|
|
|
|
|
*
|
|
|
|
|
* @param Bottom
|
|
|
|
|
* Supplies the bottom pixel coordinate of the region to update.
|
|
|
|
|
*
|
|
|
|
|
* @return This routine does not return any value.
|
|
|
|
|
*
|
|
|
|
|
* @since XT 1.0
|
|
|
|
|
*/
|
|
|
|
|
XTAPI
|
|
|
|
|
VOID
|
|
|
|
|
HL::FrameBuffer::UpdateScreenRegion(IN ULONG Left,
|
|
|
|
|
IN ULONG Top,
|
|
|
|
|
IN ULONG Right,
|
|
|
|
|
IN ULONG Bottom)
|
|
|
|
|
{
|
|
|
|
|
ULONG Line, LineBytes;
|
|
|
|
|
PCHAR Source, Destination;
|
|
|
|
|
|
|
|
|
|
/* Make sure framebuffer is already initialized and shadow buffer is ready */
|
|
|
|
|
if(FrameBufferData.Initialized == FALSE || ScreenShadowBuffer == NULLPTR)
|
|
|
|
|
{
|
|
|
|
|
/* Unable to operate on non-initialized frame buffer */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make sure parameters are valid to prevent memory corruption */
|
|
|
|
|
if(Left >= Right || Top >= Bottom || Right > FrameBufferData.Width || Bottom > FrameBufferData.Height)
|
|
|
|
|
{
|
|
|
|
|
/* Invalid region coordinates provided */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Calculate the width of the region */
|
|
|
|
|
LineBytes = (Right - Left) * FrameBufferData.BytesPerPixel;
|
|
|
|
|
|
|
|
|
|
/* Copy the specified region line by line */
|
|
|
|
|
for(Line = Top; Line < Bottom; Line++)
|
|
|
|
|
{
|
|
|
|
|
/* Calculate the source address in the shadow buffer */
|
|
|
|
|
Source = (PCHAR)ScreenShadowBuffer +
|
|
|
|
|
(Line * FrameBufferData.Pitch) +
|
|
|
|
|
(Left * FrameBufferData.BytesPerPixel);
|
|
|
|
|
|
|
|
|
|
/* Calculate the destination address in the VRAM */
|
|
|
|
|
Destination = (PCHAR)FrameBufferData.Address +
|
|
|
|
|
(Line * FrameBufferData.Pitch) +
|
|
|
|
|
(Left * FrameBufferData.BytesPerPixel);
|
|
|
|
|
|
|
|
|
|
/* Flush RAM to VRAM */
|
|
|
|
|
RTL::Memory::CopyMemory(Destination, Source, LineBytes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|