vga.c

来自「这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统」· C语言 代码 · 共 1,275 行 · 第 1/3 页

C
1,275
字号

    /* Set Scroll Region */
    ScrollRegion[0] = x1;
    ScrollRegion[1] = y1;
    ScrollRegion[2] = x2;
    ScrollRegion[3] = y2;

    /* Set current X and Y */
    curr_x = x1;
    curr_y = y1;
}

/*
 * @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(PUCHAR String)
{
    ULONG TopDelta = 14;

    /* Start looping the string */
    while (*String)
    {
        /* Treat new-line separately */
        if (*String == '\n')
        {
            /* Modify Y position */
            curr_y += TopDelta;
            if (curr_y >= ScrollRegion[3])
            {
                /* Scroll the view */
                VgaScroll(TopDelta);
                curr_y -= TopDelta;

                /* Preserve row */
                PreserveRow(curr_y, TopDelta, TRUE);
            }

            /* Update current X */
            curr_x = ScrollRegion[0];

            /* Preseve the current row */
            PreserveRow(curr_y, TopDelta, FALSE);
        }
        else if (*String == '\r')
        {
            /* Update current X */
            curr_x = ScrollRegion[0];

            /* Check if we're being followed by a new line */
            if (String[1] != '\n') NextLine = TRUE;
        }
        else
        {
            /* Check if we had a \n\r last time */
            if (NextLine)
            {
                /* We did, preserve the current row */
                PreserveRow(curr_y, TopDelta, TRUE);
                NextLine = FALSE;
            }

            /* Display this character */
            DisplayCharacter(*String, curr_x, curr_y, TextColor, 16);
            curr_x += 8;

            /* Check if we should scroll */
            if (curr_x > ScrollRegion[2])
            {
                /* Update Y position and check if we should scroll it */
                curr_y += TopDelta;
                if (curr_y > ScrollRegion[3])
                {
                    /* Do the scroll */
                    VgaScroll(TopDelta);
                    curr_y -= TopDelta;

                    /* Save the row */
                    PreserveRow(curr_y, TopDelta, TRUE);
                }

                /* Update X */
                curr_x = ScrollRegion[0];
            }
        }

        /* Get the next character */
        String++;
    }
}

/*
 * @implemented
 */
VOID
NTAPI
VidBitBlt(PUCHAR Buffer,
          ULONG Left,
          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 == 2)
    {
        /* 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(PUCHAR Buffer,
                     ULONG Left,
                     ULONG Top,
                     ULONG Width,
                     ULONG Height,
                     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 = VgaBase + (Top * 80) + (PUCHAR)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 = VgaBase + (Top * 80) + (PUCHAR)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 = VgaBase + (Top * 80) + (PUCHAR)(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);
            }
        }
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?