
#include "tcscr.h"
#include "llvesa.h"

#include <stdlib.h>
#include <math.h>

#if 0
#define PI  (3.1415926)
#define PI2 (PI/2.0)

extern int TCS_Bpp = 0;
extern int TCS_ColorMode = TCSCRRGB;

extern TCS_TPixel *TCS_Screen = NULL;
extern int       TCS_Width  = 320;
extern int       TCS_Height = 200;
extern int       TCS_Size   = 320*200;

//static byte SCREmulTbl[(1 << 12)*2];
static byte SCREmulClip[256];

extern bool TCS_Init(int w, int h, int bpp) {
    int i, j;

    TCS_End(-1);

    if (bpp == 24)
        bpp = 32;

    TCS_Width  = w;
    TCS_Height = h;

    LLV_Init();
    TCS_Bpp = bpp;

    if (bpp != 8 && bpp != 18) {
        if (LLV_SetModeRez(TCS_Width, TCS_Height, bpp))
            TCS_Bpp = bpp;
        else if (LLV_SetModeRez(TCS_Width, TCS_Height, 32))
            TCS_Bpp = 32;
        else if (LLV_SetModeRez(TCS_Width, TCS_Height, 16))
            TCS_Bpp = 16;
        else if (LLV_SetModeRez(TCS_Width, TCS_Height, 15))
            TCS_Bpp = 15;
        else
            TCS_Bpp = 8;//18;
    }

    if (TCS_Bpp != 8 && TCS_Bpp != 18) {
            // Check color order.
        switch (TCS_Bpp) {
            case 15:
            case 16:
                if (LLV_ModeInfo->RedFieldPosition == 10
                 && LLV_ModeInfo->GreenFieldPosition == 5
                 && LLV_ModeInfo->BlueFieldPosition == 0) {
                    TCS_ColorMode = TCSCRRGB;
                    TCS_Bpp = 15;
                } else if (LLV_ModeInfo->RedFieldPosition == 0
                 && LLV_ModeInfo->GreenFieldPosition == 5
                 && LLV_ModeInfo->BlueFieldPosition == 10) {
                    TCS_ColorMode = TCSCRBGR;
                    TCS_Bpp = 15;
                } else if (LLV_ModeInfo->RedFieldPosition == 11
                 && LLV_ModeInfo->GreenFieldPosition == 5
                 && LLV_ModeInfo->BlueFieldPosition == 0) {
                    TCS_ColorMode = TCSCRRGB;
                    TCS_Bpp = 16;
                } else if (LLV_ModeInfo->RedFieldPosition == 0
                 && LLV_ModeInfo->GreenFieldPosition == 5
                 && LLV_ModeInfo->BlueFieldPosition == 11) {
                    TCS_ColorMode = TCSCRBGR;
                    TCS_Bpp = 16;
                } else
                    TCS_Bpp = 8;
                break;
            case 32:
                if (LLV_ModeInfo->RedFieldPosition == 16
                 && LLV_ModeInfo->GreenFieldPosition == 8
                 && LLV_ModeInfo->BlueFieldPosition == 0)
                    TCS_ColorMode = TCSCRRGB;
                else if (LLV_ModeInfo->RedFieldPosition == 0
                 && LLV_ModeInfo->GreenFieldPosition == 8
                 && LLV_ModeInfo->BlueFieldPosition == 16)
                    TCS_ColorMode = TCSCRBGR;
                else
                    TCS_Bpp = 8;
                break;
        }
    }
    if (TCS_Bpp == 8) {
        TCS_Width = 320;
        TCS_Height = 200;
        VGA_SetMode(0x13);
        VGA_ZeroPalette();
        VGA_Tweak();
            // Set tweaked 320x400 video mode
        outb(0x3D4, 9);
        outb(0x3D5, (inb(0x3D5) & 0xE0));
        VGA_SetPlanes(0xF);
        memset(VGA800x80[0], 0, 65536);

            // Create palette for 12 bit emulation
        for (i = 0, j = 0; j < 16; i++, j++)
            VGA_PutColor(i, 0, 63*sin(PI2*(j & 15)/15.0), 0);
        for (; j < 16*16; i++, j++)
            VGA_PutColor(i, 63*sin(PI2*(j & 15)/15.0), 0, 63*sin(PI2*(j/16)/15.0));
            // Create table for 12 bit emulation
        for (i = 0; i < 256; i++) {
            if (i >= 16)
                SCREmulClip[i] = i;
            else
                SCREmulClip[i] = i + 16;
        }
    } else if (TCS_Bpp == 18) {
        TCS_Width = 320;
        TCS_Height = 160;
        VGA_SetMode(0x13);
        VGA_ZeroPalette();
        VGA_Set240();
            // Set tweaked 320x480 video mode
        outb(0x3D4, 9);
        outb(0x3D5, (inb(0x3D5) & 0xE0));
        VGA_SetPlanes(0xF);
        memset(VGA800x80[0], 0, 65536);

            // Create palette for 12 bit emulation
        i = 0;
        for (j = 0; j < 64; i++, j++)
            VGA_PutColor(i, 63*sin(PI2*j/63.0), 0, 0);
        for (j = 0; j < 64; i++, j++)
            VGA_PutColor(i, 0, 63*sin(PI2*j/63.0), 0);
        for (j = 0; j < 64; i++, j++)
            VGA_PutColor(i, 0, 0, 63*sin(PI2*j/63.0));
    } else
        LLV_SetScanlineLength(LLV_ModeInfo->XResolution, NULL);

    TCS_Size = TCS_Width*TCS_Height;
    DISPOSE(TCS_Screen);
    TCS_Screen = NEW(TCS_Size*sizeof(*TCS_Screen));
    if (TCS_Screen == NULL)
        return FALSE;
    memset(TCS_Screen, 0, TCS_Size*sizeof(*TCS_Screen));

    TCS_Dump(TCS_Screen, 0, TCS_Height);
    return TRUE;
}

extern void TCS_End(int mode) {
    LLV_End();
    DISPOSE(TCS_Screen);
    if (mode >= 0)
        VGA_SetMode(mode);
    TCS_Bpp = 0;
}

extern void DoRGB565(void *dest, int n, const TCS_TPixel *src, int dith1, int dith2);
#pragma aux DoRGB565 parm [EDI] [ECX] [ESI] [EAX] [EDX] modify [EBX EAX EDX] = \
"    PUSH    EBP                "  \
"    PUSH    EAX                "  \
"    PUSH    EDX                "  \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    MOV     EDX,[ESP]          "  \
"    MOV     EBP,EAX            "  \
"    AND     EBP,0x3C0F03C0     "  \
"    ADD     EAX,EDX            "  \
"    SHR     EBP,4              "  \
"    SUB     EAX,EBP            "  \
"    MOV     EBX,EAX            "  \
"    AND     EAX,0x3E000000     "  \
"    MOV     EDX,EBX            "  \
"    AND     EBX,0x000FC000     "  \
"    SHR     EAX,25-11          "  \
"    AND     EDX,0x000003E0     "  \
"    SHR     EBX,14-5           "  \
"    MOV     EBP,[ESI+4]        "  \
"    SHR     EDX,5              "  \
"    OR      EAX,EBX            "  \
"    MOV     EBX,EBP            "  \
"    AND     EBP,0x3C0F03C0     "  \
"    ADD     EBX,[ESP+4]        "  \
"    SHR     EBP,4              "  \
"    OR      EAX,EDX            "  \
"    SUB     EBX,EBP            "  \
"    MOV     EBP,EBX            "  \
"    MOV     EDX,EBX            "  \
"    AND     EBP,0x3E000000     "  \
"    AND     EBX,0x000FC000     "  \
"    SHL     EBP,27-25          "  \
"    AND     EDX,0x000003E0     "  \
"    SHL     EBX,21-14          "  \
"    OR      EAX,EBP            "  \
"    SHL     EDX,16-5           "  \
"    OR      EAX,EBX            "  \
"    OR      EAX,EDX            "  \
"    ADD     ESI,8              "  \
"    MOV     [EDI],EAX          "  \
"    ADD     EDI,4              "  \
"    LOOP    @@l                "  \
"    POP     EDX                "  \
"    POP     EAX                "  \
"    POP     EBP                "

/*
"    MOV     EBX,EBP            "  \
"    AND     EBX,0x3C0F03C0     "  \
"    SHR     EBX,4              "  \
"    SUB     EBP,EBX            "  \
*/

/*
extern void DoBGR565(void *dest, int n, const TCS_TPixel *src);
#pragma aux DoBGR565 parm [EDI] [ECX] [ESI] modify [EBX EAX EDX] = \
"    PUSH    EBP                "  \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    MOV     EBX,EAX            "  \
"    AND     EAX,0x3E000000     "  \
"    MOV     EDX,EBX            "  \
"    AND     EBX,0x000FC000     "  \
"    SHR     EAX,25             "  \
"    AND     EDX,0x000003E0     "  \
"    SHR     EBX,14-5           "  \
"    MOV     EBP,[ESI+4]        "  \
"    SHL     EDX,11-5           "  \
"    OR      EAX,EBX            "  \
"    MOV     EBX,EBP            "  \
"    OR      EAX,EDX            "  \
"    AND     EBP,0x3E000000     "  \
"    MOV     EDX,EBX            "  \
"    AND     EBX,0x000FC000     "  \
"    SHR     EBP,25-16          "  \
"    AND     EDX,0x000003E0     "  \
"    SHL     EBX,21-14          "  \
"    OR      EAX,EBP            "  \
"    SHL     EDX,27-5           "  \
"    OR      EAX,EBX            "  \
"    OR      EAX,EDX            "  \
"    ADD     ESI,8              "  \
"    MOV     [EDI],EAX          "  \
"    ADD     EDI,4              "  \
"    SUB     ECX,2              "  \
"    JNZ     @@l                "  \
"    POP     EBP                "
*/

extern void DoBGR565(void *dest, int n, const TCS_TPixel *src, int dith1, int dith2);
#pragma aux DoBGR565 parm [EDI] [ECX] [ESI] [EAX] [EDX] modify [EBX EAX EDX] = \
"    PUSH    EBP                "  \
"    PUSH    EAX                "  \
"    PUSH    EDX                "  \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    MOV     EDX,[ESP]          "  \
"    MOV     EBP,EAX            "  \
"    AND     EBP,0x3C0F03C0     "  \
"    ADD     EAX,EDX            "  \
"    SHR     EBP,4              "  \
"    SUB     EAX,EBP            "  \
"    MOV     EBX,EAX            "  \
"    AND     EAX,0x3E000000     "  \
"    MOV     EDX,EBX            "  \
"    AND     EBX,0x000FC000     "  \
"    SHR     EAX,25             "  \
"    AND     EDX,0x000003E0     "  \
"    SHR     EBX,14-5           "  \
"    MOV     EBP,[ESI+4]        "  \
"    SHL     EDX,11-5           "  \
"    OR      EAX,EBX            "  \
"    MOV     EBX,EBP            "  \
"    AND     EBP,0x3C0F03C0     "  \
"    ADD     EBX,[ESP+4]        "  \
"    SHR     EBP,4              "  \
"    OR      EAX,EDX            "  \
"    SUB     EBX,EBP            "  \
"    MOV     EBP,EBX            "  \
"    MOV     EDX,EBX            "  \
"    AND     EBP,0x3E000000     "  \
"    AND     EBX,0x000FC000     "  \
"    SHR     EBP,25-16          "  \
"    AND     EDX,0x000003E0     "  \
"    SHL     EBX,21-14          "  \
"    OR      EAX,EBP            "  \
"    SHL     EDX,27-5           "  \
"    OR      EAX,EBX            "  \
"    OR      EAX,EDX            "  \
"    ADD     ESI,8              "  \
"    MOV     [EDI],EAX          "  \
"    ADD     EDI,4              "  \
"    LOOP    @@l                "  \
"    POP     EDX                "  \
"    POP     EAX                "  \
"    POP     EBP                "


extern void DoRGB555(void *dest, int n, const TCS_TPixel *src);
#pragma aux DoRGB555 parm [EDI] [ECX] [ESI] modify [EBX EAX EDX] = \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    MOV     EBX,EAX            "  \
"    AND     EAX,0x3E000000     "  \
"    MOV     EDX,EBX            "  \
"    AND     EBX,0x000F8000     "  \
"    SHR     EAX,25-10          "  \
"    AND     EDX,0x000003E0     "  \
"    SHR     EBX,15-5           "  \
"    SHR     EDX,5              "  \
"    OR      EAX,EBX            "  \
"    OR      EAX,EDX            "  \
"    MOV     [EDI],AX           "  \
"    ADD     EDI,2              "  \
"    ADD     ESI,4              "  \
"    DEC     ECX                "  \
"    JNZ     @@l                "

extern void DoBGR555(void *dest, int n, const TCS_TPixel *src);
#pragma aux DoBGR555 parm [EDI] [ECX] [ESI] modify [EBX EAX EDX] = \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    MOV     EBX,EAX            "  \
"    AND     EAX,0x3E000000     "  \
"    MOV     EDX,EBX            "  \
"    AND     EBX,0x000F8000     "  \
"    SHR     EAX,25             "  \
"    AND     EDX,0x000003E0     "  \
"    SHR     EBX,15-5           "  \
"    SHL     EDX,10-5           "  \
"    OR      EAX,EBX            "  \
"    OR      EAX,EDX            "  \
"    MOV     [EDI],AX           "  \
"    ADD     EDI,2              "  \
"    ADD     ESI,4              "  \
"    DEC     ECX                "  \
"    JNZ     @@l                "

extern void DoRGB0888(void *dest, int n, const TCS_TPixel *src);
#pragma aux DoRGB0888 parm [EDI] [ECX] [ESI] modify [EBX EAX EDX] = \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    MOV     EBX,EAX            "  \
"    AND     EAX,0x3FC00000     "  \
"    MOV     EDX,EBX            "  \
"    AND     EBX,0x000FF000     "  \
"    SHR     EAX,22-16          "  \
"    AND     EDX,0x000003FC     "  \
"    SHR     EBX,12-8           "  \
"    SHR     EDX,2              "  \
"    OR      EAX,EBX            "  \
"    OR      EAX,EDX            "  \
"    MOV     [EDI],EAX          "  \
"    ADD     EDI,4              "  \
"    ADD     ESI,4              "  \
"    DEC     ECX                "  \
"    JNZ     @@l                "

extern void DoBGR0888(void *dest, int n, const TCS_TPixel *src);
#pragma aux DoBGR0888 parm [EDI] [ECX] [ESI] modify [EBX EAX EDX] = \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    MOV     EBX,EAX            "  \
"    AND     EAX,0x3FC00000     "  \
"    MOV     EDX,EBX            "  \
"    AND     EBX,0x000FF000     "  \
"    SHR     EAX,22             "  \
"    AND     EDX,0x000003FC     "  \
"    SHR     EBX,12-8           "  \
"    SHL     EDX,16-2           "  \
"    OR      EAX,EBX            "  \
"    OR      EAX,EDX            "  \
"    MOV     [EDI],EAX          "  \
"    ADD     EDI,4              "  \
"    ADD     ESI,4              "  \
"    DEC     ECX                "  \
"    JNZ     @@l                "

/*
extern void DoRGB8_0(void *dest, int n, const TCS_TPixel *src);
#pragma aux DoRGB8_0 parm [EDI] [ECX] [ESI] modify [EBX EAX EDX] = \
"    PUSH    EBP                "  \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    MOV     EBX,EAX            "  \
"    AND     EAX,0x3C000000     "  \
"    MOV     EDX,EBX            "  \
"    AND     EBX,0x000F0000     "  \
"    SHR     EAX,26-8-1         "  \
"    AND     EDX,0x000003C0     "  \
"    SHR     EBX,16-4-1         "  \
"    SHR     EDX,6-0-1          "  \
"    OR      EAX,EBX            "  \
"    OR      EAX,EDX            "  \
"    MOV     DL,[SCREmulTbl+EAX+0]     "  \
"    MOV     [EDI],DL           "  \
"    MOV     DL,[SCREmulTbl+EAX+1]     "  \
"    MOV     [EDI+80],DL        "  \
"    ADD     EDI,1              "  \
"    ADD     ESI,16             "  \
"    DEC     ECX                "  \
"    JNZ     @@l                "  \
"    POP     EBP                "

extern void DoRGB8_1(void *dest, int n, const TCS_TPixel *src);
#pragma aux DoRGB8_1 parm [EDI] [ECX] [ESI] modify [EBX EAX EDX] = \
"    PUSH    EBP                "  \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    MOV     EBX,EAX            "  \
"    AND     EAX,0x3C000000     "  \
"    MOV     EDX,EBX            "  \
"    AND     EBX,0x000F0000     "  \
"    SHR     EAX,26-8-1         "  \
"    AND     EDX,0x000003C0     "  \
"    SHR     EBX,16-4-1         "  \
"    SHR     EDX,6-0-1          "  \
"    OR      EAX,EBX            "  \
"    OR      EAX,EDX            "  \
"    MOV     DL,[SCREmulTbl+EAX+1]     "  \
"    MOV     [EDI],DL           "  \
"    MOV     DL,[SCREmulTbl+EAX+0]     "  \
"    MOV     [EDI+80],DL        "  \
"    ADD     EDI,1              "  \
"    ADD     ESI,16             "  \
"    DEC     ECX                "  \
"    JNZ     @@l                "  \
"    POP     EBP                "
*/
/*
extern void DoRGB8_00(void *dest, int n, const TCS_TPixel *src);
#pragma aux DoRGB8_00 parm [EDI] [ECX] [ESI] modify [EBX EAX EDX] = \
"    PUSH    EBP                "  \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    MOV     EBX,EAX            "  \
"    AND     EAX,0x3C000000     "  \
"    MOV     EBP,EBX            "  \
"    AND     EBX,0x000F0000     "  \
"    SHR     EAX,26-8-1         "  \
"    AND     EBP,0x000003C0     "  \
"    SHR     EBX,16-4-1         "  \
"    ADD     ESI,16             "  \
"    SHR     EBP,6-0-1          "  \
"    OR      EAX,EBX            "  \
"    ROR     EDX,8              "  \
"    OR      EAX,EBP            "  \
"    DEC     ECX                "  \
"    MOV     DL,[SCREmulTbl+EAX+0]"  \
"    TEST    ECX,3              "  \
"    JNZ     @@l                "  \
"    ROR     EDX,8              "  \
"    MOV     [EDI],EDX          "  \
"    ADD     EDI,4              "  \
"    TEST    ECX,ECX            "  \
"    JNZ     @@l                "  \
"    POP     EBP                "

extern void DoRGB8_01(void *dest, int n, const TCS_TPixel *src);
#pragma aux DoRGB8_01 parm [EDI] [ECX] [ESI] modify [EBX EAX EDX] = \
"    PUSH    EBP                "  \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    MOV     EBX,EAX            "  \
"    AND     EAX,0x3C000000     "  \
"    MOV     EBP,EBX            "  \
"    AND     EBX,0x000F0000     "  \
"    SHR     EAX,26-8-1         "  \
"    AND     EBP,0x000003C0     "  \
"    SHR     EBX,16-4-1         "  \
"    ADD     ESI,16             "  \
"    SHR     EBP,6-0-1          "  \
"    OR      EAX,EBX            "  \
"    ROR     EDX,8              "  \
"    OR      EAX,EBP            "  \
"    DEC     ECX                "  \
"    MOV     DL,[SCREmulTbl+EAX+1]"  \
"    TEST    ECX,3              "  \
"    JNZ     @@l                "  \
"    ROR     EDX,8              "  \
"    MOV     [EDI],EDX          "  \
"    ADD     EDI,4              "  \
"    TEST    ECX,ECX            "  \
"    JNZ     @@l                "  \
"    POP     EBP                "
*/

extern void DoRGB8_00(void *dest, int n, const TCS_TPixel *src, int dith);
#pragma aux DoRGB8_00 parm [EDI] [ECX] [ESI] [EBX] modify [EBX EAX EDX] = \
"    PUSH    EBP                "  \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    MOV     EBP,EAX            "  \
"    AND     EBP,0x3C0F03C0     "  \
"    SHR     EBP,4              "  \
"    ADD     EAX,EBX            "  \
"    SUB     EAX,EBP            "  \
"    MOV     EBP,EAX            "  \
"    AND     EAX,0x3C000000     "  \
"    AND     EBP,0x000003C0     "  \
"    SHR     EAX,26-0           "  \
"    ADD     ESI,16             "  \
"    SHR     EBP,6-4            "  \
"    ROR     EDX,8              "  \
"    OR      EAX,EBP            "  \
"    DEC     ECX                "  \
"    MOV     DL,[SCREmulClip+EAX]"  \
"    TEST    ECX,3              "  \
"    JNZ     @@l                "  \
"    ROR     EDX,8              "  \
"    MOV     [EDI],EDX          "  \
"    ADD     EDI,4              "  \
"    TEST    ECX,ECX            "  \
"    JNZ     @@l                "  \
"    POP     EBP                "

extern void DoRGB8_01(void *dest, int n, const TCS_TPixel *src, int dith);
#pragma aux DoRGB8_01 parm [EDI] [ECX] [ESI] [EBX] modify [EBX EAX EDX] = \
"    PUSH    EBP                "  \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    MOV     EBP,EAX            "  \
"    AND     EBP,0x3C0F03C0     "  \
"    SHR     EBP,4              "  \
"    ADD     EAX,EBX            "  \
"    SUB     EAX,EBP            "  \
"    ADD     ESI,16             "  \
"    AND     EAX,0x000F0000     "  \
"    ROR     EDX,8              "  \
"    DEC     ECX                "  \
"    SHR     EAX,16             "  \
"    TEST    ECX,3              "  \
"    MOV     DL,AL              "  \
"    JNZ     @@l                "  \
"    ROR     EDX,8              "  \
"    MOV     [EDI],EDX          "  \
"    ADD     EDI,4              "  \
"    TEST    ECX,ECX            "  \
"    JNZ     @@l                "  \
"    POP     EBP                "

extern void DoRGB18_00(void *dest, int n, const TCS_TPixel *src);
#pragma aux DoRGB18_00 parm [EDI] [ECX] [ESI] modify [EBX EAX EDX] = \
"    PUSH    EBP                "  \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    ADD     ESI,16             "  \
"    AND     EAX,0x3F000000     "  \
"    ROR     EDX,8              "  \
"    DEC     ECX                "  \
"    SHR     EAX,24             "  \
"    TEST    ECX,3              "  \
"    MOV     DL,AL              "  \
"    JNZ     @@l                "  \
"    ROR     EDX,8              "  \
"    MOV     [EDI],EDX          "  \
"    ADD     EDI,4              "  \
"    TEST    ECX,ECX            "  \
"    JNZ     @@l                "  \
"    POP     EBP                "

extern void DoRGB18_01(void *dest, int n, const TCS_TPixel *src);
#pragma aux DoRGB18_01 parm [EDI] [ECX] [ESI] modify [EBX EAX EDX] = \
"    PUSH    EBP                "  \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    ADD     ESI,16             "  \
"    AND     EAX,0x000FC000     "  \
"    ROR     EDX,8              "  \
"    ADD     EAX,0x00100000     "  \
"    DEC     ECX                "  \
"    SHR     EAX,14             "  \
"    TEST    ECX,3              "  \
"    MOV     DL,AL              "  \
"    JNZ     @@l                "  \
"    ROR     EDX,8              "  \
"    MOV     [EDI],EDX          "  \
"    ADD     EDI,4              "  \
"    TEST    ECX,ECX            "  \
"    JNZ     @@l                "  \
"    POP     EBP                "

extern void DoRGB18_02(void *dest, int n, const TCS_TPixel *src);
#pragma aux DoRGB18_02 parm [EDI] [ECX] [ESI] modify [EBX EAX EDX] = \
"    PUSH    EBP                "  \
"  @@l:                         "  \
"    MOV     EAX,[ESI]          "  \
"    ADD     ESI,16             "  \
"    AND     EAX,0x000003F0     "  \
"    ROR     EDX,8              "  \
"    ADD     EAX,0x00000800     "  \
"    DEC     ECX                "  \
"    SHR     EAX,4              "  \
"    TEST    ECX,3              "  \
"    MOV     DL,AL              "  \
"    JNZ     @@l                "  \
"    ROR     EDX,8              "  \
"    MOV     [EDI],EDX          "  \
"    ADD     EDI,4              "  \
"    TEST    ECX,ECX            "  \
"    JNZ     @@l                "  \
"    POP     EBP                "

extern void TCS_Dump(const TCS_TPixel *org, int miny, int maxy) {
    int lw;
    int o, b, r;
    byte *p, *end;
    int i, j, w;
    const TCS_TPixel *eorg;

    if (miny >= maxy)
        return;
/*
    if (miny < 0)
        miny = 0;
    if (maxy > TCS_Height)
        maxy = TCS_Height;
*/
    if (TCS_Bpp == 8) {
        const TCS_TPixel *s;

        w = TCS_Width/4;
        for (i = miny; i < maxy; i++) {
            s = org;
            p = VGA800x80[2*i];
            for (j = 1; j < 16; j <<= 1) {
                VGA_SetPlanes(j);
                if (j & 0x5) {
                    if (i & 1) {
                        DoRGB8_00(p, w, s, 0x02008020);
                        DoRGB8_01(p+80, w, s, 0x01004010);
                    } else {
                        DoRGB8_00(p, w, s, 0x01004010);
                        DoRGB8_01(p+80, w, s, 0x02008020);
                    }
                } else {
                    if (i & 1) {
                        DoRGB8_00(p+80, w, s, 0x0300C020);
                        DoRGB8_01(p, w, s, 0x00000000);
                    } else {
                        DoRGB8_00(p+80, w, s, 0x00000000);
                        DoRGB8_01(p, w, s, 0x0300C030);
                    }
                }
                s++;
            }
            org += TCS_Width;
        }
        return;
    } else if (TCS_Bpp == 18) {
        int i, j, w;
        const TCS_TPixel *s;

        w = TCS_Width/4;
        for (i = miny; i < maxy; i++) {
            s = org;
            p = VGA800x80[3*i];
            for (j = 1; j < 16; j <<= 1) {
                VGA_SetPlanes(j);
                DoRGB18_00(p+0*80, w, s);
                DoRGB18_01(p+1*80, w, s);
                DoRGB18_02(p+2*80, w, s);
                s++;
            }
            org += TCS_Width;
        }
        return;
    }

    o  = TCS_Width*miny*((TCS_Bpp+1)/8);
        // Number of bytes to dump.
    lw = TCS_Width*(maxy - miny)*((TCS_Bpp+1)/8);
    b  = LLV_BANK(o);
    p  = LLV_WinAddr[LLV_WriteWindow] + LLV_OFFS(o);
    end = LLV_WinAddr[LLV_WriteWindow] + LLV_WinSize;
    i = miny;
    j = 0;
    while (lw > 0) {
        r = end - p;    // Number of bytes till end of window
        if (r > lw)     // Dump until before end?
            r = lw;
        if (r < 0)
            BASE_Abort("r == %d, lw = %d, end = 0x%X, p = 0x%X, BankRatio = %d\n",
                       r, lw, end, p, LLV_BankRatio);
        LLV_SetWindow(LLV_WriteWindow, b);
        switch(TCS_Bpp) {
            case 15:
                if (TCS_ColorMode == TCSCRRGB)
                    DoRGB555(p, r/2, org);
                else
                    DoBGR555(p, r/2, org);
                org += r/2;
                break;
            case 16:
                eorg = org + r/2;
                while (org < eorg) {
                    int myr = TCS_Width - j;
                    if (org + myr > eorg)
                        myr = eorg - org;
                    if (TCS_ColorMode == TCSCRRGB)
                        if (i & 1)
                            DoRGB565(p, myr >> 1, org, 0x01002010, 0x00000000);
                        else
                            DoRGB565(p, myr >> 1, org, 0x00801008, 0x01803018);
                    else
                        if (i & 1)
                            DoBGR565(p, myr >> 1, org, 0x01002010, 0x00000000);
                        else
                            DoBGR565(p, myr >> 1, org, 0x00801008, 0x01803018);
                    j += myr;
                    if (j >= TCS_Width) {
                        j = 0;
                        i++;
                    }
                    org += myr;
                    p += myr*2;
                }
                break;
            case 32:
                if (TCS_ColorMode == TCSCRRGB)
                    DoRGB0888(p, r/4, org);
                else
                    DoBGR0888(p, r/4, org);
                org += r/4;
                break;
        }
//        break;
        p = LLV_WinAddr[LLV_WriteWindow];
        lw  -= r;
        b   += LLV_BankRatio;
    }
}

extern void TCS_SetPage(int nline) {
    if (TCS_Bpp == 8 || TCS_Bpp == 18)
        VGA_SetDisplayPage(nline*TCS_Width/2);
    else
        LLV_SetDisplayStart(0, nline);
}
#endif