/*
 * SoftPC Revision 3.0
 *
 * Title        : Win32 VGA Graphics Module
 *
 * Description  :
 *
 *              This modules contain the Win32 specific functions required
 *              to support the VGA emulation.
 *
 * Author       : Jerry Sexton (based on X_vga.c)
 *
 * Notes        :
 *
 */

#include <windows.h>
#include "insignia.h"
#include "host_def.h"

#include "xt.h"
#undef TEXT
#include "gvi.h"
#include "gmi.h"
#include "gfx_upd.h"
#include <stdio.h>
#include "trace.h"
#include "debug.h"
#include "egagraph.h"
#include "egacpu.h"
#include "egaports.h"
#include "host_rrr.h"
#include "..\..\..\..\windows\inc\conapi.h"

#include "nt_graph.h"

#ifdef MONITOR       
#include <ntddvdeo.h>
#include "nt_fulsc.h"
#endif /* MONITOR */ 

IMPORT int DisplayErrorTerm(int, DWORD, char *, int);

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:::::::::::::::::::: Initialise VGA hi res graphics ::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_init_vga_hi_graph()
{
    sub_note_trace0(EGA_HOST_VERBOSE, "nt_init_vga_hi_graph");

    /* Set up the number of bits per pixel for this mode. */
    sc.BitsPerPixel = VGA_BITS_PER_PIXEL;
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:::::: Paint function (256 colour mode PC 320x200. SoftPC 640x400.):::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_graph_std(int offset, int screen_x, int screen_y,
                      int width, int height )
{
    register unsigned short *dest_ptr;
    register unsigned short *ref_dest_ptr;
    register unsigned char *data_ptr;
    register unsigned char *ref_data_ptr;
    register int local_height;
    register int i, temp, bpl, shorts_per_scanline;
    int max_width = sc.PC_W_Width >> 1,
        max_height = sc.PC_W_Height >> 1;
    SMALL_RECT rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                    "nt_vga_graph_std off=%d x=%d y=%d width=%d height=%d\n",
                    offset, screen_x, screen_y, width, height );
    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }

    /* If the image is completely outside the display area do nothing. */
    if ((screen_x >= max_width) || (screen_y >= max_height))
    {
        sub_note_trace2(EGA_HOST_VERBOSE,
                        "VDM: nt_vga_graph_std() x=%d y=%d",
                        screen_x, screen_y);
        return;
    }

    /*
     * If image partially overlaps display area clip it so we don't start
     * overwriting invalid pieces of memory.
     */
    if (screen_x + width > max_width)
        width = max_width - screen_x;
    if (screen_y + height > max_height)
        height = max_height - screen_y;

    /*
     * Build up the bitmap: each PC pixel is stored in video memory as one
     * byte (i.e. 8 bits-per-pixel); each PC pixel is translated to a square
     * block of 4 host pixels.
     */
    bpl = get_bytes_per_line();
    shorts_per_scanline = SHORTS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
    local_height = height;
    ref_data_ptr = &EGA_plane0123[offset];
    ref_dest_ptr = (unsigned short *) sc.ConsoleBufInfo.lpBitMap +
                   (screen_y << 1) * shorts_per_scanline + screen_x;

    /* Grab the mutex. */
    GrabMutex(sc.ConsoleBufInfo.hMutex);

    /* Build up the bitmap. */
    do
    {
        dest_ptr = ref_dest_ptr;
        data_ptr = ref_data_ptr;

        for( i = 0; i < width; i++ )
        {
            temp = *data_ptr++;
            *(dest_ptr + shorts_per_scanline) = *dest_ptr =
                                         (unsigned short)((temp << 8) | temp);
            dest_ptr++;
        }
        ref_dest_ptr += 2 * shorts_per_scanline;
        ref_data_ptr += bpl;
    }
    while( --local_height );

    /* Release the mutex. */
    RelMutex(sc.ConsoleBufInfo.hMutex);

    /* Display the new image. */
    rect.Left = screen_x << 1;
    rect.Top = screen_y << 1;
    rect.Right = rect.Left + (width << 1) - 1;
    rect.Bottom = rect.Top + (height << 1) - 1;

    if( sc.ScreenBufHandle )
        if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
        //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*Paint function (256 colour mode PC 320x200. SoftPC 640x400.) on big screen*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_graph_big(int offset, int screen_x, int screen_y,
                      int width, int height)
{
#ifdef BIGWIN
    register unsigned short *dest_ptr;
    register unsigned short *ref_dest_ptr;
    register unsigned char *data_ptr;
    register unsigned char *ref_data_ptr;
    register int local_height;
    register int i;
    register int temp1;
    register int temp2;
    register int half_width;
    register int bpl;
    int shorts_per_scanline;
    int max_width = UNSCALE(sc.PC_W_Width) >> 1,
        max_height = UNSCALE(sc.PC_W_Height) >> 1;
    SMALL_RECT rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                    "nt_vga_graph_big off=%d x=%d y=%d width=%d height=%d\n",
                    offset, screen_x, screen_y, width, height );

    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }

    /* If the image is completely outside the display area do nothing. */
    if ((screen_x >= max_width) || (screen_y >= max_height))
    {
        sub_note_trace2(EGA_HOST_VERBOSE,
                        "VDM: nt_vga_med_graph_std() x=%d y=%d",
                        screen_x, screen_y);
        return;
    }

    /*
     * If image partially overlaps display area clip it so we don't start
     * overwriting invalid pieces of memory.
     */
    if (screen_x + width > max_width)
        width = max_width - screen_x;
    if (screen_y + height > max_height)
        height = max_height - screen_y;

    bpl = get_bytes_per_line();
    shorts_per_scanline = SHORTS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
    local_height = height;
    ref_data_ptr = &EGA_plane0123[offset];
    ref_dest_ptr = (unsigned short *) sc.ConsoleBufInfo.lpBitMap +
                   SCALE(screen_y << 1) * shorts_per_scanline +
                   SCALE(screen_x);
    half_width = width >> 1;

    /* Grab the mutex. */
    GrabMutex(sc.ConsoleBufInfo.hMutex);

    do
    {
        dest_ptr = ref_dest_ptr;
        data_ptr = ref_data_ptr;

        for( i = 0; i < half_width; i++ )
        {
            temp1 = *data_ptr++;
            temp2 = *data_ptr++;

            *(dest_ptr + 2 * shorts_per_scanline) =
                *(dest_ptr + shorts_per_scanline) =
                *dest_ptr = (unsigned short) ((temp1 << 8) | temp1);

            *(dest_ptr + (2 * shorts_per_scanline) + 1) =
                *(dest_ptr + shorts_per_scanline + 1) =
#ifdef BIGEND
                *(dest_ptr + 1) = (unsigned short) ((temp1 << 8) | temp2);
#endif /* BIGEND */
#ifdef LITTLEND
                *(dest_ptr + 1) = (unsigned short) ((temp2 << 8) | temp1);
#endif /* LITTLEND */

            *(dest_ptr + (2 * shorts_per_scanline) + 2) =
                *(dest_ptr + shorts_per_scanline + 2) =
                *(dest_ptr + 2) = (unsigned short) ((temp2 << 8) | temp2);

            dest_ptr += 3;
        }

        ref_dest_ptr += 3 * shorts_per_scanline;
        ref_data_ptr += bpl;
    }
    while( --local_height );

    /* Release the mutex. */
    RelMutex(sc.ConsoleBufInfo.hMutex);

    /* Display the new image. */
    rect.Left = SCALE(screen_x << 1);
    rect.Top = SCALE(screen_y << 1);
    rect.Right = rect.Left + SCALE(width << 1) - 1;
    rect.Bottom = rect.Top + SCALE(height << 1) - 1;

    if( sc.ScreenBufHandle )
        if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
        //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__);
#endif /* BIGWIN */
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*: Paint function (256 colour mode PC 320x200. SoftPC 1280x800.) on huge  :*/
/*: screen.                                                                :*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_graph_huge(int offset, int screen_x, int screen_y,
                       int width, int height)
{
#ifdef BIGWIN
    unsigned char *dest_ptr;
    unsigned char *line_ptr;
    unsigned char *ref_dest_ptr;
    unsigned char *data_ptr;
    unsigned char *ref_data_ptr;
    int local_height;
    int i;
    byte temp;
    int bpl;
    int max_width = UNSCALE(sc.PC_W_Width) >> 1,
        max_height = UNSCALE(sc.PC_W_Height) >> 1;
    SMALL_RECT rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                    "nt_vga_graph_huge off=%d x=%d y=%d width=%d height=%d\n",
                    offset, screen_x, screen_y, width, height );

    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }

    /* If the image is completely outside the display area do nothing. */
    if ((screen_x >= max_width) || (screen_y >= max_height))
    {
        sub_note_trace2(EGA_HOST_VERBOSE,
                        "VDM: nt_vga_med_graph_std() x=%d y=%d",
                        screen_x, screen_y);
        return;
    }

    /*
     * If image partially overlaps display area clip it so we don't start
     * overwriting invalid pieces of memory.
     */
    if (screen_x + width > max_width)
        width = max_width - screen_x;
    if (screen_y + height > max_height)
        height = max_height - screen_y;

    bpl = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
    local_height = height;
    ref_data_ptr = &EGA_plane0123[offset];
    ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap +
                   SCALE(screen_y << 1) * bpl +
                   SCALE(screen_x << 1);

    /* Grab the mutex. */
    GrabMutex(sc.ConsoleBufInfo.hMutex);

    do
    {
        line_ptr = ref_dest_ptr;
        data_ptr = ref_data_ptr;

        for(i = 0; i < width; i++)
        {
            dest_ptr = line_ptr;
            temp = *data_ptr++;

            /* line 1 */
            *dest_ptr++ = temp;
            *dest_ptr++ = temp;
            *dest_ptr++ = temp;
            *dest_ptr = temp;

            dest_ptr = line_ptr + bpl;

            /* line 2 */
            *dest_ptr++ = temp;
            *dest_ptr++ = temp;
            *dest_ptr++ = temp;
            *dest_ptr = temp;

            dest_ptr = line_ptr + 2 * bpl;

            /* line 3 */
            *dest_ptr++ = temp;
            *dest_ptr++ = temp;
            *dest_ptr++ = temp;
            *dest_ptr = temp;

            dest_ptr = line_ptr + 3 * bpl;

            /* line 4 */
            *dest_ptr++ = temp;
            *dest_ptr++ = temp;
            *dest_ptr++ = temp;
            *dest_ptr = temp;

            line_ptr += 4;
        }

        ref_dest_ptr += FOUR_SCANLINES * bpl;
        ref_data_ptr += 320;
    }
    while( --local_height );

    /* Release the mutex. */
    RelMutex(sc.ConsoleBufInfo.hMutex);

    /* Display the new image. */
    rect.Left = SCALE(screen_x << 1);
    rect.Top = SCALE(screen_y << 1);
    rect.Right = rect.Left + SCALE(width << 1) - 1;
    rect.Bottom = rect.Top + SCALE(height << 1) - 1;

    if( sc.ScreenBufHandle )
        if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
        //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__);
#endif /* BIGWIN */
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*Paint function (256 colour mode PC 320x200. SoftPC 640x400.)              */
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

/* The data for this mode is split over all four vga planes and is interlaced
   4 way onto the screen. Hence 4 pixels horizontally for every pixel that the
   base detects. Pixels are not doubled vertically. */

void nt_vga_med_graph_std(int offset, int screen_x, int screen_y,
                         int width, int height)
{
    ULONG       *p0,
                *ref_p0,
                *dest_ptr,
                *ref_dest_ptr,
                data;
    UTINY       data0,
                data1,
                data2,
                data3;
    int  local_height,
         i,
         longs_per_scanline;
    SMALL_RECT   rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                   "nt_vga_med_graph_std off=%d x=%d y=%d width=%d height=%d\n",
                   offset, screen_x, screen_y, width, height);

    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }

    /* This mode doubles vertically so, multiply vertical parameters by 2. */
    screen_y <<= 1;
    height <<= 1;

    /* If the image is completely outside the display area do nothing. */
    if (((screen_x << 3) >= sc.PC_W_Width) || (screen_y >= sc.PC_W_Height))
    {
        sub_note_trace2(EGA_HOST_VERBOSE,
                        "VDM: nt_vga_med_graph_std() x=%d y=%d",
                        screen_x, screen_y);
        return;
    }

    /*
     * If image partially overlaps display area clip it so we don't start
     * overwriting invalid pieces of memory.
     */
    if (((screen_x + width) << 3) > sc.PC_W_Width)
        width = (sc.PC_W_Width >> 3) - screen_x;
    if (screen_y + height > sc.PC_W_Height)
        height = sc.PC_W_Height - screen_y;

    /* local_height is number of lines in video memory. */
    local_height = height >> 1;

    /* Get pointer to video memory. */
    ref_p0 = (ULONG *) get_regen_ptr(0, offset << 2);

    /* Get pointer to bitmap. */
    longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
    ref_dest_ptr = (ULONG *) sc.ConsoleBufInfo.lpBitMap +
                   screen_y * longs_per_scanline + (screen_x << 1);

    /* Grab the mutex. */
    GrabMutex(sc.ConsoleBufInfo.hMutex);

    /* Munge. */
    do
    {
        dest_ptr = ref_dest_ptr;
        p0 = ref_p0;

        for(i = 0; i < width; i++)
        {

            /*
             * Get data and output to screen buffer. NOTE little endian
             * dependent code.
             */
            data = *p0++;
            data0 = (UTINY) (data & 0xff);
            data1 = (UTINY) ((data >> 8) & 0xff);
            data2 = (UTINY) ((data >> 16) & 0xff);
            data3 = (UTINY) (data >> 24);

            *(dest_ptr + longs_per_scanline) = *dest_ptr =
                (data1 << 24) | (data1 << 16) | (data0 << 8) | data0;
            dest_ptr++;
            *(dest_ptr + longs_per_scanline) = *dest_ptr =
                (data3 << 24) | (data3 << 16) | (data2 << 8) | data2;
            dest_ptr++;
        }

        ref_dest_ptr += 2 * longs_per_scanline;
        ref_p0 += get_offset_per_line();
    }
    while(--local_height);

    /* Release the mutex. */
    RelMutex(sc.ConsoleBufInfo.hMutex);

    /* Display the new image. */
    rect.Left = screen_x << 3;
    rect.Top = screen_y;
    rect.Right = rect.Left + (width << 3) - 1;
    rect.Bottom = rect.Top + height - 1;

    if( sc.ScreenBufHandle )
        if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
        //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*Paint function (256 colour mode PC 320x200. SoftPC 960x600.)              */
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

/* The data for this mode is split over all four vga planes and is interlaced
   4 way onto the screen. Hence 4 pixels horizontally for every pixel that the
   base detects. Pixels are not doubled vertically. */

void nt_vga_med_graph_big(int offset, int screen_x, int screen_y,
                         int width, int height)
{
    ULONG       *p0,
                *ref_p0,
                *dest_ptr,
                *ref_dest_ptr,
                data;
    UTINY       data0,
                data1,
                data2,
                data3;
    int  local_height,
         i,
         longs_per_scanline,
         max_width = UNSCALE(sc.PC_W_Width) >> 3,
         max_height = UNSCALE(sc.PC_W_Height);
    SMALL_RECT   rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                   "nt_vga_med_graph_big off=%d x=%d y=%d width=%d height=%d\n",
                   offset, screen_x, screen_y, width, height);

    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }

    /* This mode doubles vertically so, multiply vertical parameters by 2. */
    screen_y <<= 1;
    height <<= 1;

    /* If the image is completely outside the display area do nothing. */
    if ((screen_x >= max_width) || (screen_y >= max_height))
    {
        sub_note_trace2(EGA_HOST_VERBOSE,
                        "VDM: nt_vga_med_graph_big() x=%d y=%d",
                        screen_x, screen_y);
        return;
    }

    /*
     * If image partially overlaps display area clip it so we don't start
     * overwriting invalid pieces of memory.
     */
    if (screen_x + width > max_width)
        width = max_width - screen_x;
    if (screen_y + height > max_height)
        height = max_height - screen_y;

    /* local_height is number of lines in video memory. */
    local_height = height >> 1;

    /* Get pointer to video memory. */
    ref_p0 = (ULONG *) get_regen_ptr(0, offset << 2);

    /* Get pointer to bitmap. */
    longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
    ref_dest_ptr = (ULONG *) sc.ConsoleBufInfo.lpBitMap +
                   SCALE(screen_y) * longs_per_scanline + SCALE(screen_x << 1);

    /* Grab the mutex. */
    GrabMutex(sc.ConsoleBufInfo.hMutex);

    /* Munge. */
    do
    {
        dest_ptr = ref_dest_ptr;
        p0 = ref_p0;

        for(i = 0; i < width; i++)
        {

            /*
             * Get data and output to screen buffer. NOTE little endian
             * dependent code.
             */
            data = *p0++;
            data0 = (UTINY) (data & 0xff);
            data1 = (UTINY) ((data >> 8) & 0xff);
            data2 = (UTINY) ((data >> 16) & 0xff);
            data3 = (UTINY) (data >> 24);

            *(dest_ptr + 2 * longs_per_scanline) =
                *(dest_ptr + longs_per_scanline) =
                *dest_ptr =
                (data1 << 24) | (data0 << 16) | (data0 << 8) | data0;
            dest_ptr++;
            *(dest_ptr + 2 * longs_per_scanline) =
                *(dest_ptr + longs_per_scanline) =
                *dest_ptr =
                (data2 << 24) | (data2 << 16) | (data1 << 8) | data1;
            dest_ptr++;
            *(dest_ptr + 2 * longs_per_scanline) =
                *(dest_ptr + longs_per_scanline) =
                *dest_ptr =
                (data3 << 24) | (data3 << 16) | (data3 << 8) | data2;
            dest_ptr++;
        }

        ref_dest_ptr += 3 * longs_per_scanline;
        ref_p0 += get_offset_per_line();
    }
    while(--local_height);

    /* Release the mutex. */
    RelMutex(sc.ConsoleBufInfo.hMutex);

    /* Display the new image. */
    rect.Left = SCALE(screen_x << 3);
    rect.Top = SCALE(screen_y);
    rect.Right = rect.Left + SCALE(width << 3) - 1;
    rect.Bottom = rect.Top + SCALE(height) - 1;

    if( sc.ScreenBufHandle )
        if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
        //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*Paint function (256 colour mode PC 320x200. SoftPC 1080x800.)              */
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

/* The data for this mode is split over all four vga planes and is interlaced
   4 way onto the screen. Hence 4 pixels horizontally for every pixel that the
   base detects. Pixels are not doubled vertically. */

void nt_vga_med_graph_huge(int offset, int screen_x, int screen_y,
                          int width, int height)
{
    ULONG       *p0,
                *ref_p0,
                *dest_ptr,
                *ref_dest_ptr,
                data;
    UTINY       data0,
                data1,
                data2,
                data3;
    int  local_height,
         i,
         longs_per_scanline,
         max_width = UNSCALE(sc.PC_W_Width) >> 3,
         max_height = UNSCALE(sc.PC_W_Height);
    SMALL_RECT   rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                   "nt_vga_med_graph_huge off=%d x=%d y=%d width=%d height=%d\n",
                   offset, screen_x, screen_y, width, height);

    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }

    /* This mode doubles vertically so, multiply vertical parameters by 2. */
    screen_y <<= 1;
    height <<= 1;

    /* If the image is completely outside the display area do nothing. */
    if ((screen_x >= max_width) || (screen_y >= max_height))
    {
        sub_note_trace2(EGA_HOST_VERBOSE,
                        "VDM: nt_vga_med_graph_huge() x=%d y=%d",
                        screen_x, screen_y);
        return;
    }

    /*
     * If image partially overlaps display area clip it so we don't start
     * overwriting invalid pieces of memory.
     */
    if (screen_x + width > max_width)
        width = max_width - screen_x;
    if (screen_y + height > max_height)
        height = max_height - screen_y;

    /* local_height is number of lines in video memory. */
    local_height = height >> 1;

    /* Get pointer to video memory. */
    ref_p0 = (ULONG *) get_regen_ptr(0, offset << 2);

    /* Get pointer to bitmap. */
    longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
    ref_dest_ptr = (ULONG *) sc.ConsoleBufInfo.lpBitMap +
                   SCALE(screen_y) * longs_per_scanline + SCALE(screen_x << 1);

    /* Grab the mutex. */
    GrabMutex(sc.ConsoleBufInfo.hMutex);

    /* Munge. */
    do
    {
        dest_ptr = ref_dest_ptr;
        p0 = ref_p0;

        for(i = 0; i < width; i++)
        {

            /*
             * Get data and output to screen buffer. NOTE little endian
             * dependent code.
             */
            data = *p0++;
            data0 = (UTINY) (data & 0xff);
            data1 = (UTINY) ((data >> 8) & 0xff);
            data2 = (UTINY) ((data >> 16) & 0xff);
            data3 = (UTINY) (data >> 24);

            *(dest_ptr + 3 * longs_per_scanline) =
                *(dest_ptr + 2 * longs_per_scanline) =
                *(dest_ptr + longs_per_scanline) =
                *dest_ptr =
                (data0 << 24) | (data0 << 16) | (data0 << 8) | data0;
            dest_ptr++;
            *(dest_ptr + 3 * longs_per_scanline) =
                *(dest_ptr + 2 * longs_per_scanline) =
                *(dest_ptr + longs_per_scanline) =
                *dest_ptr =
                (data1 << 24) | (data1 << 16) | (data1 << 8) | data1;
            dest_ptr++;
            *(dest_ptr + 3 * longs_per_scanline) =
                *(dest_ptr + 2 * longs_per_scanline) =
                *(dest_ptr + longs_per_scanline) =
                *dest_ptr =
                (data2 << 24) | (data2 << 16) | (data2 << 8) | data2;
            dest_ptr++;
            *(dest_ptr + 3 * longs_per_scanline) =
                *(dest_ptr + 2 * longs_per_scanline) =
                *(dest_ptr + longs_per_scanline) =
                *dest_ptr =
                (data3 << 24) | (data3 << 16) | (data3 << 8) | data3;
            dest_ptr++;
        }

        ref_dest_ptr += 4 * longs_per_scanline;
        ref_p0 += get_offset_per_line();
    }
    while(--local_height);

    /* Release the mutex. */
    RelMutex(sc.ConsoleBufInfo.hMutex);

    /* Display the new image. */
    rect.Left = SCALE(screen_x << 3);
    rect.Top = SCALE(screen_y);
    rect.Right = rect.Left + SCALE(width << 3) - 1;
    rect.Bottom = rect.Top + SCALE(height) - 1;

    if( sc.ScreenBufHandle )
        if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
        //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*Paint function (256 colour mode PC 320x400. SoftPC 640x400.)              */
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

/* The data for this mode is split over all four vga planes and is interlaced
   4 way onto the screen. Hence 4 pixels horizontally for every pixel that the
   base detects. Pixels are not doubled vertically. */

void nt_vga_hi_graph_std(int offset, int screen_x, int screen_y,
                         int width, int height)
{
    unsigned char   *p0,
                    *ref_p0,
                    *dest_ptr,
                    *ref_dest_ptr,
                     data0,
                     data1,
                     data2,
                     data3;
    int  local_height,
         i,
         bpl,
         max_width = sc.PC_W_Width >> 3;
    SMALL_RECT   rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                   "nt_vga_hi_graph_std off=%d x=%d y=%d width=%d height=%d\n",
                   offset, screen_x, screen_y, width, height);

    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }

    /* If the image is completely outside the display area do nothing. */
    if ((screen_x >= max_width) || (screen_y >= sc.PC_W_Height))
    {
        sub_note_trace2(EGA_HOST_VERBOSE,
                        "VDM: nt_vga_hi_graph_std() x=%d y=%d",
                        screen_x, screen_y);
        return;
    }

    /*
     * If image partially overlaps display area clip it so we don't start
     * overwriting invalid pieces of memory.
     */
    if (screen_x + width > max_width)
        width = max_width - screen_x;
    if (screen_y + height > sc.PC_W_Height)
        height = sc.PC_W_Height - screen_y;

    /* local_height is number of lines in video memory. */
    local_height = height;

    /* Get pointer to video memory. */
    ref_p0 = get_regen_ptr(0, offset << 2);

    /* Get pointer to bitmap. */
    bpl = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
    ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap +
                   screen_y * bpl + (screen_x << 3);

    /* Grab the mutex. */
    GrabMutex(sc.ConsoleBufInfo.hMutex);

    /* Munge. */
    do
    {
        dest_ptr = ref_dest_ptr;
        p0 = ref_p0;

        for(i = 0; i < width; i++)
        {
            data0 = *p0++;
            data1 = *p0++;
            data2 = *p0++;
            data3 = *p0++;

            *dest_ptr       = data0;
            *(dest_ptr + 1) = data0;
            *(dest_ptr + 2) = data1;
            *(dest_ptr + 3) = data1;
            *(dest_ptr + 4) = data2;
            *(dest_ptr + 5) = data2;
            *(dest_ptr + 6) = data3;
            *(dest_ptr + 7) = data3;
            dest_ptr += 8;
        }

        ref_dest_ptr += bpl;
        ref_p0 += 4 * get_offset_per_line();
    }
    while( --local_height );

    /* Release the mutex. */
    RelMutex(sc.ConsoleBufInfo.hMutex);

    /* Display the new image. */
    rect.Left = screen_x << 3;
    rect.Top = screen_y;
    rect.Right = rect.Left + (width << 3) - 1;
    rect.Bottom = rect.Top + height - 1;

    if( sc.ScreenBufHandle )
        if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
        //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::Paint function (256 colour mode PC 320(360)x400. SoftPC 920(1080)x600)::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_hi_graph_big(int offset, int screen_x, int screen_y,
                         int width, int height)
{
    unsigned char   *p0,
                    *ref_p0,
                    *dest_ptr,
                    *nl_dest_ptr,
                    *ref_dest_ptr,
                     data0,
                     data1,
                    data2,
                     data3;
    int  local_height,
         draw_height,
         local_screen_y,
         i,
         bpl,
         max_width = UNSCALE(sc.PC_W_Width) >> 3,
         max_height = UNSCALE(sc.PC_W_Height);
    BOOL     two_lines;
    SMALL_RECT   rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                    "nt_vga_hi_graph_big off=%d x=%d y=%d width=%d height=%d\n",
                    offset, screen_x, screen_y, width, height);

    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }

    /* If the image is completely outside the display area do nothing. */
    if ((screen_x >= max_width) || (screen_y >= max_height))
    {
        sub_note_trace2(EGA_HOST_VERBOSE,
                        "VDM: nt_vga_hi_graph_big() x=%d y=%d",
                        screen_x, screen_y);
        return;
    }

    /*
     * If image partially overlaps display area clip it so we don't start
     * overwriting invalid pieces of memory.
     */
    if (screen_x + width > max_width)
        width = max_width - screen_x;
    if (screen_y + height > max_height)
        height = max_height - screen_y;

    /* Get pointer to video memory. */
    ref_p0 = get_regen_ptr(0, offset << 2);

    /* Get pointer to bitmap. */
    local_screen_y = SCALE(screen_y + 1) - 1;
    bpl = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
    ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap +
                   local_screen_y * bpl +
                   SCALE(screen_x << 3);

    /* Set up local parameters. */
    local_height = height;
    draw_height = 0;

    /*
     * 2 lines are output to the SoftPC screen if this is an odd line, 1 line
     * if it is even.
     */
    two_lines = screen_y & 1 ? FALSE : TRUE;

    /* Grab the mutex. */
    GrabMutex(sc.ConsoleBufInfo.hMutex);

    /* Munge. */
    do
    {
        dest_ptr = ref_dest_ptr;
        p0 = ref_p0;

        for( i = 0; i < width; i++ )
        {
            data0 = *p0++;
            data1 = *p0++;
            data2 = *p0++;
            data3 = *p0++;

            *dest_ptr        = data0;
            *(dest_ptr + 1)  = data0;
            *(dest_ptr + 2)  = data0;
            *(dest_ptr + 3)  = data1;
            *(dest_ptr + 4)  = data1;
            *(dest_ptr + 5)  = data1;
            *(dest_ptr + 6)  = data2;
            *(dest_ptr + 7)  = data2;
            *(dest_ptr + 8)  = data2;
            *(dest_ptr + 9)  = data3;
            *(dest_ptr + 10) = data3;
            *(dest_ptr + 11) = data3;

            if (two_lines)
            {
                nl_dest_ptr = dest_ptr + bpl;

                *nl_dest_ptr        = data0;
                *(nl_dest_ptr + 1)  = data0;
                *(nl_dest_ptr + 2)  = data0;
                *(nl_dest_ptr + 3)  = data1;
                *(nl_dest_ptr + 4)  = data1;
                *(nl_dest_ptr + 5)  = data1;
                *(nl_dest_ptr + 6)  = data2;
                *(nl_dest_ptr + 7)  = data2;
                *(nl_dest_ptr + 8)  = data2;
                *(nl_dest_ptr + 9)  = data3;
                *(nl_dest_ptr + 10) = data3;
                *(nl_dest_ptr + 11) = data3;
            }
            dest_ptr += 12;
        }

        if (two_lines)
        {
            draw_height += 2;
            ref_dest_ptr += 2 * bpl;
        }
        else
        {
            draw_height++;
            ref_dest_ptr += bpl;
        }
        two_lines = !two_lines;

        ref_p0 += 4 * get_offset_per_line();
    }
    while( --local_height );

    /* Release the mutex. */
    RelMutex(sc.ConsoleBufInfo.hMutex);

    /* Display the new image. */
    rect.Left = SCALE(screen_x << 3);
    rect.Top = local_screen_y;
    rect.Right = rect.Left + SCALE(width << 3) - 1;
    rect.Bottom = rect.Top + draw_height - 1;

    if( sc.ScreenBufHandle )
        if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
        //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::Paint function (256 colour mode PC 320(360)x400. SoftPC 1280(1440)x800::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_hi_graph_huge(int offset, int screen_x, int screen_y,
                          int width, int height )
{
    unsigned char   *p0,
                    *ref_p0,
                    *dest_ptr,
                    *nl_dest_ptr,
                    *ref_dest_ptr,
                     data0,
                     data1,
                     data2,
                     data3;
    int  local_height,
         i,
         bpl,
         max_width = UNSCALE(sc.PC_W_Width) >> 3,
         max_height = UNSCALE(sc.PC_W_Height);
    SMALL_RECT   rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                   "nt_vga_hi_graph_huge off=%d x=%d y=%d width=%d height=%d\n",
                    offset, screen_x, screen_y, width, height);

    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }

    /* If the image is completely outside the display area do nothing. */
    if ((screen_x >= max_width) || (screen_y >= max_height))
    {
        sub_note_trace2(EGA_HOST_VERBOSE,
                        "VDM: nt_vga_hi_graph_huge() x=%d y=%d",
                        screen_x, screen_y);
        return;
    }

    /*
     * If image partially overlaps display area clip it so we don't start
     * overwriting invalid pieces of memory.
     */
    if (screen_x + width > max_width)
        width = max_width - screen_x;
    if (screen_y + height > max_height)
        height = max_height - screen_y;

    /* local_height is number of lines in video memory. */
    local_height = height;

    /* Get pointer to video memory. */
    ref_p0 = get_regen_ptr(0, offset << 2);

    /* Get pointer to bitmap. */
    bpl = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
    ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap +
                   SCALE(screen_y) * bpl +
                   SCALE(screen_x << 3);

    /* Munge. */
    do
    {
        dest_ptr = ref_dest_ptr;
        p0 = ref_p0;

        for(i = 0; i < width; i++)
        {
            data0 = *p0++;
            data1 = *p0++;
            data2 = *p0++;
            data3 = *p0++;

            nl_dest_ptr = dest_ptr + bpl;

            *dest_ptr = *nl_dest_ptr = data0;
            *(dest_ptr + 1) = *(nl_dest_ptr + 1) = data0;
            *(dest_ptr + 2) = *(nl_dest_ptr + 2) = data0;
            *(dest_ptr + 3) = *(nl_dest_ptr + 3) = data0;
            *(dest_ptr + 4) = *(nl_dest_ptr + 4) = data1;
            *(dest_ptr + 5) = *(nl_dest_ptr + 5) = data1;
            *(dest_ptr + 6) = *(nl_dest_ptr + 6) = data1;
            *(dest_ptr + 7) = *(nl_dest_ptr + 7) = data1;
            *(dest_ptr + 8) = *(nl_dest_ptr + 8) = data2;
            *(dest_ptr + 9) = *(nl_dest_ptr + 9) = data2;
            *(dest_ptr + 10) = *(nl_dest_ptr + 10) = data2;
            *(dest_ptr + 11) = *(nl_dest_ptr + 11) = data2;
            *(dest_ptr + 12) = *(nl_dest_ptr + 12) = data3;
            *(dest_ptr + 13) = *(nl_dest_ptr + 13) = data3;
            *(dest_ptr + 14) = *(nl_dest_ptr + 14) = data3;
            *(dest_ptr + 15) = *(nl_dest_ptr + 15) = data3;

            dest_ptr += 16;
        }

        ref_dest_ptr += 2 * bpl;
        ref_p0 += 4 * get_offset_per_line();
    }
    while(--local_height);

    /* Release the mutex. */
    RelMutex(sc.ConsoleBufInfo.hMutex);

    /* Display the new image. */
    rect.Left = SCALE(screen_x << 3);
    rect.Top = SCALE(screen_y);
    rect.Right = rect.Left + SCALE(width << 3) - 1;
    rect.Bottom = rect.Top + SCALE(height) - 1;

    if( sc.ScreenBufHandle )
        if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
        //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::::: Paint function (256 colour mode: PC 320x200. SoftPC 640x400 ::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_mono_graph_std(int offset, int screen_x, int screen_y,
                           int width, int height)
{
sub_note_trace5(EGA_HOST_VERBOSE,
  "nt_vga_mono_graph_std off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n",
   offset, screen_x, screen_y, width, height);
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*Paint function (256 colour mode: PC 320x200. SoftPC 960x600) on big screen*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void  nt_vga_mono_graph_big(int offset, int screen_x, int screen_y,
                            int width, int height)
{
sub_note_trace5(EGA_HOST_VERBOSE,
  "nt_vga_mono_graph_big off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n",
   offset, screen_x, screen_y, width, height);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*: Paint function (256 colour mode: PC 320x200. SoftPC 1280x800) on huge  :*/
/*: screen.                                                                :*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_mono_graph_huge(int offset, int screen_x, int screen_y,
                            int width, int height)
{
sub_note_trace5(EGA_HOST_VERBOSE,
    "nt_vga_mono_graph_huge off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n",
    offset, screen_x, screen_y, width, height);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::: Paint function (256Col mode : PC 320(360)x400. SoftPC 640(720)x400) ::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

/*  The data for this mode is split over all four vga planes and is interlaced
    4 way onto the screen. Hence 4 pixels horizontally for every pixel that the
    base detects. Pixels are not doubled vertically. */


void nt_vga_mono_med_graph_std(int offset, int screen_x, int screen_y,
                              int width, int height)
{
sub_note_trace5(EGA_HOST_VERBOSE,
  "nt_vga_mono_med_graph_std off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n",
   offset, screen_x, screen_y, width, height);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::: Paint function (256Col mode : PC 320(360)x400. SoftPC 920(1080)x600 ::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_mono_med_graph_big(int offset, int screen_x, int screen_y,
                              int width, int height)
{
sub_note_trace5(EGA_HOST_VERBOSE,
  "nt_vga_mono_med_graph_big off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n",
   offset, screen_x, screen_y, width, height);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::: Paint function (256Col mode: PC 320(360)x400. SoftPC 1280(1440)x400 ::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_mono_med_graph_huge(int offset, int screen_x, int screen_y,
                               int width, int height)
{
sub_note_trace5(EGA_HOST_VERBOSE,
    "nt_vga_mono_med_graph_huge off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n",
    offset, screen_x, screen_y, width, height );
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::: Paint function (256Col mode : PC 320(360)x400. SoftPC 640(720)x400) ::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

/*  The data for this mode is split over all four vga planes and is interlaced
    4 way onto the screen. Hence 4 pixels horizontally for every pixel that the
    base detects. Pixels are not doubled vertically. */


void nt_vga_mono_hi_graph_std(int offset, int screen_x, int screen_y,
                              int width, int height)
{
sub_note_trace5(EGA_HOST_VERBOSE,
  "nt_vga_mono_hi_graph_std off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n",
   offset, screen_x, screen_y, width, height);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::: Paint function (256Col mode : PC 320(360)x400. SoftPC 920(1080)x600 ::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_mono_hi_graph_big(int offset, int screen_x, int screen_y,
                              int width, int height)
{
sub_note_trace5(EGA_HOST_VERBOSE,
  "nt_vga_mono_hi_graph_big off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n",
   offset, screen_x, screen_y, width, height);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::: Paint function (256Col mode: PC 320(360)x400. SoftPC 1280(1440)x400 ::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_mono_hi_graph_huge(int offset, int screen_x, int screen_y,
                               int width, int height)
{
sub_note_trace5(EGA_HOST_VERBOSE,
    "nt_vga_mono_hi_graph_huge off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n",
    offset, screen_x, screen_y, width, height );
}

#ifdef V7VGA
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:::::::: 256 colour mode: PC 640x400, 640x480, 720x540, 800x600. :::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_v7vga_hi_graph_std(int offset, int screen_x, int screen_y,
                           int width, int height)
{
    register unsigned char *dest_ptr;
    register unsigned char *ref_dest_ptr;
    register unsigned char *data_ptr;
    register unsigned char *ref_data_ptr;
    register int local_height;
    register int i;
    int bytes_per_line;
    SMALL_RECT rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                  "nt_v7vga_hi_graph_std off=%d x=%d y=%d width=%d height=%d\n",
                    offset, screen_x, screen_y, width, height);

    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }
    /*
    ** Tim Septemver 92, sanity check parameters, if they're too big
    ** it can cause a crash.
    */
    if( height>400 || width>640 ){
        assert2( NO, "VDM: nt_v7vga_hi_graph_std() w=%d h=%d", width, height );
        return;
    }

    local_height = height;
    bytes_per_line = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
    ref_data_ptr = &EGA_plane0123[offset];
    ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap +
                   screen_y * bytes_per_line +
                   screen_x;

    /* Grab the mutex. */
    GrabMutex(sc.ConsoleBufInfo.hMutex);

    do
    {
        dest_ptr = ref_dest_ptr;
        data_ptr = ref_data_ptr;

        for(i = 0; i < width; i++)
            *dest_ptr++ = *data_ptr++;

        ref_dest_ptr += bytes_per_line;
        ref_data_ptr += get_offset_per_line();
    }
    while( --local_height );

    /* Release the mutex. */
    RelMutex(sc.ConsoleBufInfo.hMutex);

    /* Display the new image. */
    rect.Left = screen_x;
    rect.Top = screen_y;
    rect.Right = rect.Left + width - 1;
    rect.Bottom = rect.Top + height - 1;

    if( sc.ScreenBufHandle )
        if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
        //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:::::::: 256 colour mode: PC 640x400, 640x480, 720x540, 800x600. :::::::::*/
/*:::::::: SoftPC 960x600, 960x720, 1080x810, 1200x900.            :::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_v7vga_hi_graph_big(int offset, int screen_x, int screen_y,
                           int width, int height)
{
    register unsigned char *dest_ptr;
    register unsigned char *ref_dest_ptr;
    register unsigned char *data_ptr;
    register unsigned char *ref_data_ptr;
    register int local_height=0;
    register int i, temp1, temp2;
    register int half_width = width >> 1;
    int bytes_per_line;
    int local_screen_y;
    BOOL two_lines;
    SMALL_RECT rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                  "nt_v7vga_hi_graph_big off=%d x=%d y=%d width=%d height=%d\n",
                    offset, screen_x, screen_y, width, height );

    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }
    /*
    ** Tim September 92, sanity check parameters, if they're too big
    ** it can cause a crash.
    */
    if( height>400 || width>640 ){
        assert2( NO, "VDM: nt_v7vga_hi_graph_big() w=%d h=%d", width, height );
        return;
    }

    /* Get pointer to data in EGA_planes. */
    ref_data_ptr = (unsigned char *) &EGA_plane0123[offset] +
                   (height - 1) * get_offset_per_line();

    /*
     * Get pointer into bitmap, which alternates 2 lines and 1 line so that,
     * memory line 0 -> bitmap 0,
     *             1 ->        2,
     *             2 ->        3,
     *             3 ->        5,
     *             4 ->        6 etc.
     * hence the local_screen_y assignment.
     */
    local_screen_y = SCALE(screen_y + 1) - 1;
    bytes_per_line = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
    ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap +
                   local_screen_y * bytes_per_line +
                   SCALE(screen_x);

    /* Decide whether to start with 1 or 2 scanlines. */
    two_lines = screen_y & 1 ? FALSE : TRUE;

    /* Grab the mutex. */
    GrabMutex(sc.ConsoleBufInfo.hMutex);

    do
    {
        dest_ptr = ref_dest_ptr;
        data_ptr = ref_data_ptr;

        for(i = 0; i < half_width; i++)
        {
            temp1 = *data_ptr++;
            temp2 = *data_ptr++;
            *dest_ptr = (unsigned char) temp1;
            *(dest_ptr+2) = (unsigned char) temp2;

            if (two_lines)
            {
                *(dest_ptr+1) = (unsigned char) temp1;
                *(dest_ptr + bytes_per_line) = (unsigned char) temp1;
                *(dest_ptr + bytes_per_line + 1) = (unsigned char) temp2;
                *(dest_ptr + bytes_per_line + 2) = (unsigned char) temp2;
            }
            else
            {
                *(dest_ptr+1) = (unsigned char) temp2;
            }
            dest_ptr+=3;

        }

        ref_data_ptr += get_offset_per_line();
        if (two_lines)
        {
            local_height += 2;
            ref_dest_ptr += 2 * bytes_per_line;
        }
        else
        {
            local_height++;
            ref_dest_ptr += bytes_per_line;
        }
        two_lines = !two_lines;
    }
    while(--height);

    /* Release the mutex. */
    RelMutex(sc.ConsoleBufInfo.hMutex);

    /* Display the new image. */
    rect.Left = SCALE(screen_x);
    rect.Top = local_screen_y;
    rect.Right = rect.Left + SCALE(width) - 1;
    rect.Bottom = rect.Top + local_height - 1;

    if( sc.ScreenBufHandle )
        if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
        //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:::::::: 256 colour mode: PC 640x400, 640x480, 720x540, 800x600. :::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_v7vga_hi_graph_huge(int offset, int screen_x, int screen_y,
                            int width, int height)
{
    register unsigned char *dest_ptr;
    register unsigned char *ref_dest_ptr;
    register unsigned char *data_ptr;
    register unsigned char *ref_data_ptr;
    register int local_height;
    register int i;
    int bytes_per_line;
    SMALL_RECT rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                 "nt_v7vga_hi_graph_huge off=%d x=%d y=%d width=%d height=%d\n",
                    offset, screen_x, screen_y, width, height);

    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }
    /*
    ** Tim September 92, sanity check parameters, if they're too big
    ** it can cause a crash.
    */
    if( height>400 || width>640 ){
        assert2( NO, "VDM: nt_v7vga_hi_graph_huge() w=%d h=%d", width, height );
        return;
    }

    local_height = height;
    bytes_per_line = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
    ref_data_ptr = &EGA_plane0123[offset];
    ref_dest_ptr = (unsigned char *) sc.ConsoleBufInfo.lpBitMap +
                   SCALE(screen_y) * bytes_per_line +
                   SCALE(screen_x);

    /* Grab the mutex. */
    GrabMutex(sc.ConsoleBufInfo.hMutex);

    do
    {
        dest_ptr = ref_dest_ptr;
        data_ptr = ref_data_ptr;

        for(i = 0; i < width; i++)
        {
            *dest_ptr = *(dest_ptr + bytes_per_line) = *data_ptr;
            *(dest_ptr + 1) = *(dest_ptr + 1 + bytes_per_line) = *data_ptr++;
            dest_ptr += 2;
        }

        ref_dest_ptr -= 2 * bytes_per_line;
        ref_data_ptr += get_offset_per_line();
    }
    while(--local_height);

    /* Release the mutex. */
    RelMutex(sc.ConsoleBufInfo.hMutex);

    /* Display the new image. */
    rect.Left = SCALE(screen_x);
    rect.Top = SCALE(screen_y);
    rect.Right = rect.Left + SCALE(width) - 1;
    rect.Bottom = rect.Top + SCALE(height) - 1;

    if( sc.ScreenBufHandle )
        if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
        //DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:::::::: 256 colour mode: PC 640x400, 640x480, 720x540, 800x600. :::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_v7vga_mono_hi_graph_std(int offset, int screen_x, int screen_y,
                                int width, int height)
{
sub_note_trace5(EGA_HOST_VERBOSE,
    "nt_v7vga_mono_hi_graph_std off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n",
    offset, screen_x, screen_y, width, height);
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:::::::: 256 colour mode: PC 640x400, 640x480, 720x540, 800x600. :::::::::*/
/*:::::::: SoftPC 960x600, 960x720, 1080x810, 1200x900.            :::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_v7vga_mono_hi_graph_big(int offset, int screen_x, int screen_y,
                                int width, int height )
{
sub_note_trace5(EGA_HOST_VERBOSE,
    "nt_v7vga_mono_hi_graph_big off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n",
    offset, screen_x, screen_y, width, height );
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:::::::: 256 colour mode: PC 640x400, 640x480, 720x540, 800x600. :::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_v7vga_mono_hi_graph_huge(int offset, int screen_x, int screen_y,
                                 int width, int height)
{
sub_note_trace5(EGA_HOST_VERBOSE,
    "nt_v7vga_mono_hi_graph_huge off=%d x=%d y=%d width=%d height=%d - NOT SUPPORTED\n",
    offset, screen_x, screen_y, width, height);
}
#endif /* V7VGA */

#ifdef MONITOR
/* There are 2 possible formats for the standard 256 colour VGA mode. One (VGA,
 * S3, Ultra etc) has shape 1/ below, the other (ET4000, WD) has a packed
 * format more like emulation /2.
 * The Miniport sets a flag to tell use which format to use.
 *
 *  1/  uses paint routine nt_vga_frozen_std
 *      Regen Memory:   XYABJKLM
 *      Plane 0: X...J...
 *      Plane 1: .Y...K..
 *      Plane 2: ..A...L.
 *      Plane 3: ...B...M.
 *      (plus a 1 byte skip every 16k).
 *
 *  2/  uses paint routine nt_vga_frozen_pack_std
 *      Regen Memory:   XYABJKLM
 *      Plane 0: XJ..
 *      Plane 1: YK..
 *      Plane 2: AL..
 *      Plane 3: BM..
 *
 */
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::: Frozen paint function (256 colour mode PC 320x200. SoftPC 640x400.):::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_frozen_std(int offset, int screen_x, int screen_y,
                       int width, int height)
{
    USHORT	*dest_ptr,
		*ref_dest_ptr;
    UTINY	*plane1_ptr,
		*plane2_ptr,
		*plane3_ptr,
		*plane4_ptr;
    ULONG	 local_width,
		 local_height,
		 byte_shift,
		 mem_loc,
		 temp,
		 bpl,
		 shorts_per_scanline,
		 max_width = sc.PC_W_Width >> 1,
		 max_height = sc.PC_W_Height >> 1;
    SMALL_RECT	 rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                    "nt_vga_frozen_std off=%d x=%d y=%d width=%d height=%d\n",
                    offset, screen_x, screen_y, width, height );
    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }

    /* If the image is completely outside the display area do nothing. */
    if (((ULONG)screen_x >= max_width) || ((ULONG) screen_y >= max_height))
    {
        sub_note_trace2(EGA_HOST_VERBOSE,
                        "VDM: nt_vga_frozen_std() x=%d y=%d",
                        screen_x, screen_y);
        return;
    }

    /*
     * If image partially overlaps display area clip it so we don't start
     * overwriting invalid pieces of memory.
     */
    if (screen_x + width > (int)max_width)
        width = max_width - screen_x;
    if ((ULONG) (screen_y + height) > max_height)
        height = max_height - screen_y;

    /* memory involved here liable to be suddenly removed due to fs switch */
    try
    {
        /*
         * Build up the bitmap: each PC pixel is stored in video memory as one
         * byte (i.e. 8 bits-per-pixel); each PC pixel is translated to a square
         * block of 4 host pixels.
         */
        bpl = get_bytes_per_line();
        shorts_per_scanline = SHORTS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
        local_height = height;
        ref_dest_ptr = (unsigned short *) sc.ConsoleBufInfo.lpBitMap +
                       (screen_y << 1) * shorts_per_scanline + screen_x;

        /*
         * The data stored in the bit-planes is shifted left by one byte every
         * 16k bytes.
         */
        byte_shift = offset / 0x4000;
        offset += byte_shift;

        /* Set up the plane pointers. */
        plane1_ptr = GET_OFFSET(Plane1Offset);
        plane2_ptr = GET_OFFSET(Plane2Offset);
        plane3_ptr = GET_OFFSET(Plane3Offset);
        plane4_ptr = GET_OFFSET(Plane4Offset);

        /* Grab the mutex. */
        GrabMutex(sc.ConsoleBufInfo.hMutex);

        /* Build up the bitmap. */
        do
        {
            dest_ptr = ref_dest_ptr;
	    mem_loc = offset;
	    local_width = width >> 2;

	    do
            {

	        /* Every 4k bytes the data gets shifted by 1 byte. */
	        if (mem_loc / 0x4000 != byte_shift)
	        {
		mem_loc++;
		offset++;
		byte_shift++;
	        }
	        temp = *(plane1_ptr + mem_loc);
                *(dest_ptr + shorts_per_scanline) = *dest_ptr =
                                         (unsigned short)((temp << 8) | temp);
                dest_ptr++;
	        temp = *(plane2_ptr + mem_loc);
                *(dest_ptr + shorts_per_scanline) = *dest_ptr =
                                         (unsigned short)((temp << 8) | temp);
                dest_ptr++;
	        temp = *(plane3_ptr + mem_loc);
                *(dest_ptr + shorts_per_scanline) = *dest_ptr =
                                         (unsigned short)((temp << 8) | temp);
                dest_ptr++;
	        temp = *(plane4_ptr + mem_loc);
                *(dest_ptr + shorts_per_scanline) = *dest_ptr =
                                         (unsigned short)((temp << 8) | temp);
                dest_ptr++;
	        mem_loc += 4;
            }
	    while (--local_width);
            ref_dest_ptr += 2 * shorts_per_scanline;
	    offset += bpl;
        }
        while(--local_height);

        /* Release the mutex. */
        RelMutex(sc.ConsoleBufInfo.hMutex);

        /* Display the new image. */
        rect.Left = screen_x << 1;
        rect.Top = screen_y << 1;
        rect.Right = rect.Left + (width << 1) - 1;
        rect.Bottom = rect.Top + (height << 1) - 1;

        if( sc.ScreenBufHandle )
            if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                    assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
    } except(EXCEPTION_EXECUTE_HANDLER)
      {
          assert0(NO, "Handled fault in nt_vga_frozen_std. fs switch?");
          return;
      }
}


/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/* Frozen paint function (256 colour mode packed. PC 320x200 SoftPC 640x400.)*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
void nt_vga_frozen_pack_std(int offset, int screen_x, int screen_y,
                       int width, int height)
{
    USHORT	*dest_ptr,
		*ref_dest_ptr;
    UTINY	*plane1_ptr,
		*plane2_ptr,
		*plane3_ptr,
		*plane4_ptr;
    ULONG	 local_width,
		 local_height,
		 mem_loc,
		 temp,
		 bpl,
		 shorts_per_scanline,
		 max_width = sc.PC_W_Width >> 1,
		 max_height = sc.PC_W_Height >> 1;
    SMALL_RECT	 rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                 "nt_vga_frozen_pack_std off=%d x=%d y=%d width=%d height=%d\n",
                 offset, screen_x, screen_y, width, height );
    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }

    /* If the image is completely outside the display area do nothing. */
    if (((ULONG)screen_x >= max_width) || ((ULONG) screen_y >= max_height))
    {
        sub_note_trace2(EGA_HOST_VERBOSE,
                        "VDM: nt_vga_frozen_std() x=%d y=%d",
                        screen_x, screen_y);
        return;
    }

    /*
     * If image partially overlaps display area clip it so we don't start
     * overwriting invalid pieces of memory.
     */
    if (screen_x + width > (int)max_width)
        width = max_width - screen_x;
    if ((ULONG) (screen_y + height) > max_height)
        height = max_height - screen_y;

    /* memory involved here liable to be suddenly removed due to fs switch */
    try
    {
        /*
         * Build up the bitmap: each PC pixel is stored in video memory as one
         * byte (i.e. 8 bits-per-pixel); each PC pixel is translated to a square
         * block of 4 host pixels.
         */
        bpl = get_bytes_per_line() >> 2;
        shorts_per_scanline = SHORTS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
        local_height = height;
        ref_dest_ptr = (unsigned short *) sc.ConsoleBufInfo.lpBitMap +
                       (screen_y << 1) * shorts_per_scanline + screen_x;

        /* Set up the plane pointers. */
        plane1_ptr = GET_OFFSET(Plane1Offset);
        plane2_ptr = GET_OFFSET(Plane2Offset);
        plane3_ptr = GET_OFFSET(Plane3Offset);
        plane4_ptr = GET_OFFSET(Plane4Offset);

        /* Grab the mutex. */
        GrabMutex(sc.ConsoleBufInfo.hMutex);

        /* Build up the bitmap. */
        do
        {
            dest_ptr = ref_dest_ptr;
	    mem_loc = offset;
	    local_width = width >> 2;

	    do
            {

	        temp = *(plane1_ptr + mem_loc);
                *(dest_ptr + shorts_per_scanline) = *dest_ptr =
                                         (unsigned short)((temp << 8) | temp);
                dest_ptr++;
	        temp = *(plane2_ptr + mem_loc);
                *(dest_ptr + shorts_per_scanline) = *dest_ptr =
                                         (unsigned short)((temp << 8) | temp);
                dest_ptr++;
	        temp = *(plane3_ptr + mem_loc);
                *(dest_ptr + shorts_per_scanline) = *dest_ptr =
                                         (unsigned short)((temp << 8) | temp);
                dest_ptr++;
	        temp = *(plane4_ptr + mem_loc);
                *(dest_ptr + shorts_per_scanline) = *dest_ptr =
                                         (unsigned short)((temp << 8) | temp);
                dest_ptr++;
	        mem_loc ++;
            }
	    while (--local_width);
            ref_dest_ptr += 2 * shorts_per_scanline;
	    offset += bpl;
        }
        while(--local_height);

        /* Release the mutex. */
        RelMutex(sc.ConsoleBufInfo.hMutex);

        /* Display the new image. */
        rect.Left = screen_x << 1;
        rect.Top = screen_y << 1;
        rect.Right = rect.Left + (width << 1) - 1;
        rect.Bottom = rect.Top + (height << 1) - 1;

        if( sc.ScreenBufHandle )
            if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                    assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
    } except(EXCEPTION_EXECUTE_HANDLER)
      {
          assert0(NO, "Handled fault in nt_vga_frozen_std. fs switch?");
          return;
      }
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/* Frozen paint function (256 colour mode PC 320x200. SoftPC 640x400.)      */
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_med_frozen_std(int offset, int screen_x, int screen_y,
                           int width, int height)
{
    ULONG	*dest_ptr,
		*ref_dest_ptr,
		 max_width = sc.PC_W_Width >> 3,
		 max_height = sc.PC_W_Height >> 1,
		 bpl,
		 local_height,
		 local_width,
		 longs_per_scanline,
		 mem_loc;
    UTINY	 data0,
		 data1,
		 data2,
		 data3,
		*plane1_ptr,
		*plane2_ptr,
		*plane3_ptr,
		*plane4_ptr;
    SMALL_RECT   rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                   "nt_vga_med_frozen_std off=%d x=%d y=%d width=%d height=%d\n",
                   offset, screen_x, screen_y, width, height);

    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }

    /* If the image is completely outside the display area do nothing. */
    if (((ULONG)screen_x >= max_width) || ((ULONG) screen_y >= max_height))
    {
        sub_note_trace2(EGA_HOST_VERBOSE,
                        "VDM: nt_vga_med_frozen_std() x=%d y=%d",
                        screen_x, screen_y);
        return;
    }

    /*
     * If image partially overlaps display area clip it so we don't start
     * overwriting invalid pieces of memory.
     */
    if (screen_x + width > (int)max_width)
        width = max_width - screen_x;
    if ((ULONG) (screen_y + height) > max_height)
        height = max_height - screen_y;

    /* local_height is number of lines in video memory. */
    local_height = height;

    /* memory involved here liable to be suddenly removed due to fs switch */
    try
    {
        /* Get pointer to video memory. */
        bpl = get_bytes_per_line();
        plane1_ptr = GET_OFFSET(Plane1Offset);
        plane2_ptr = GET_OFFSET(Plane2Offset);
        plane3_ptr = GET_OFFSET(Plane3Offset);
        plane4_ptr = GET_OFFSET(Plane4Offset);

        /* Get pointer to bitmap. */
        longs_per_scanline = LONGS_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
        ref_dest_ptr = (ULONG *) sc.ConsoleBufInfo.lpBitMap +
                   (screen_y << 1) * longs_per_scanline + (screen_x << 1);

        /* Grab the mutex. */
        GrabMutex(sc.ConsoleBufInfo.hMutex);

        /* Munge. */
        do
        {
            dest_ptr = ref_dest_ptr;
	    mem_loc = offset;
	    local_width = width;

            do
            {

                /*
                 * Get data and output to screen buffer. NOTE little endian
                 * dependent code.
                 */
                data0 = *(plane1_ptr + mem_loc);
                data1 = *(plane2_ptr + mem_loc);
                data2 = *(plane3_ptr + mem_loc);
                data3 = *(plane4_ptr + mem_loc);

                *(dest_ptr + longs_per_scanline) = *dest_ptr =
                    (data1 << 24) | (data1 << 16) | (data0 << 8) | data0;
                dest_ptr++;
                *(dest_ptr + longs_per_scanline) = *dest_ptr =
                    (data3 << 24) | (data3 << 16) | (data2 << 8) | data2;
                dest_ptr++;
	        mem_loc++;
            }
	    while (--local_width);

            ref_dest_ptr += 2 * longs_per_scanline;
	    offset += bpl;
        }
        while(--local_height);

        /* Release the mutex. */
        RelMutex(sc.ConsoleBufInfo.hMutex);

        /* Display the new image. */
        rect.Left = screen_x << 3;
        rect.Top = screen_y << 1;
        rect.Right = rect.Left + (width << 3) - 1;
        rect.Bottom = rect.Top + (height << 1) - 1;

        if( sc.ScreenBufHandle )
            if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
    } except(EXCEPTION_EXECUTE_HANDLER)
      {
          assert0(NO, "Handled fault in nt_vga_med_frozen_std. fs switch?");
          return;
      }
}

/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/* Hi-res frozen paint func (256 colour mode PC 320x400. SoftPC 640x400.)   */
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/

void nt_vga_hi_frozen_std(int offset, int screen_x, int screen_y,
                          int width, int height)
{
    UTINY	*dest_ptr,
		*ref_dest_ptr,
		*plane1_ptr,
		*plane2_ptr,
		*plane3_ptr,
		*plane4_ptr;
    ULONG	 local_height,
		 local_width,
		 mem_loc,
		 bytes_per_scanline,
		 bpl,
		 max_width = sc.PC_W_Width >> 3,
		 max_height = sc.PC_W_Height;
    SMALL_RECT	 rect;

    sub_note_trace5(EGA_HOST_VERBOSE,
                   "nt_vga_hi_frozen_std off=%d x=%d y=%d width=%d height=%d\n",
                   offset, screen_x, screen_y, width, height);

    /*
    ** Tim September 92, bounce call if handle to screen buffer is null.
    ** This can happen when VDM session is about to suspend, buffer has
    ** been closed, but still get a paint request.
    */
    if( sc.ScreenBufHandle == (HANDLE)NULL ){
        assert0( NO, "VDM: rejected paint request due to NULL handle" );
        return;
    }

    /* If the image is completely outside the display area do nothing. */
    if (((ULONG)screen_x >= max_width) || ((ULONG) screen_y >= max_height))
    {
        sub_note_trace2(EGA_HOST_VERBOSE,
                        "VDM: nt_vga_hi_frozen_std() x=%d y=%d",
                        screen_x, screen_y);
        return;
    }

    /*
     * If image partially overlaps display area clip it so we don't start
     * overwriting invalid pieces of memory.
     */
    if (screen_x + width > (int)max_width)
        width = max_width - screen_x;
    if ((ULONG) (screen_y + height) > max_height)
        height = max_height - screen_y;

    /* memory involved here liable to be suddenly removed due to fs switch */
    try
    {
        /* local_height is number of lines in video memory. */
        local_height = height;

        /* Get pointer to bitmap. */
        bpl = get_bytes_per_line();
        bytes_per_scanline = BYTES_PER_SCANLINE(sc.ConsoleBufInfo.lpBitMapInfo);
        ref_dest_ptr = (UTINY *) sc.ConsoleBufInfo.lpBitMap +
                       screen_y * bytes_per_scanline + (screen_x << 3);

        /* Set up the plane pointers. */
        plane1_ptr = GET_OFFSET(Plane1Offset);
        plane2_ptr = GET_OFFSET(Plane2Offset);
        plane3_ptr = GET_OFFSET(Plane3Offset);
        plane4_ptr = GET_OFFSET(Plane4Offset);

        /* Grab the mutex. */
        GrabMutex(sc.ConsoleBufInfo.hMutex);

        /* Build up the bitmap. */
        do
        {
            dest_ptr = ref_dest_ptr;
	    mem_loc = offset;
	    local_width = width;

	    do
            {
                *(dest_ptr + 1) = *dest_ptr = *(plane1_ptr + mem_loc);
                dest_ptr += 2;
                *(dest_ptr + 1) = *dest_ptr = *(plane2_ptr + mem_loc);
                dest_ptr += 2;
                *(dest_ptr + 1) = *dest_ptr = *(plane3_ptr + mem_loc);
                dest_ptr += 2;
                *(dest_ptr + 1) = *dest_ptr = *(plane4_ptr + mem_loc);
                dest_ptr += 2;
	        mem_loc++;
            }
	    while (--local_width);
            ref_dest_ptr += bytes_per_scanline;
	    offset += bpl;
        }
        while(--local_height);

        /* Release the mutex. */
        RelMutex(sc.ConsoleBufInfo.hMutex);

        /* Display the new image. */
        rect.Left = (screen_x << 3);
        rect.Top = screen_y;
        rect.Right = rect.Left + (width << 3) - 1;
        rect.Bottom = rect.Top + height - 1;

        if( sc.ScreenBufHandle )
            if (!InvalidateConsoleDIBits(sc.ScreenBufHandle, &rect))
                assert1( NO, "VDM: InvalidateConsoleDIBits() error:%#x",
                         GetLastError() );
    } except(EXCEPTION_EXECUTE_HANDLER)
      {
          assert0(NO, "Handled fault in nt_vga_hi_frozen_std. fs switch?");
          return;
      }
}
#endif /* MONITOR */
