#include "executor.h"
#include "kvidha.h"
#include "sb.h"
#include "newdb.h"

static unsigned char MMXBuffer[8];

void DBFillScreen(unsigned long c)
{
    int i;
    unsigned long *p;
    
    p = (unsigned long *)DblBuffer;
    for(i = 0; i < 64000; i++)
	*(p++) = c;
}

void DBSetClip(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2)
{
    clip_x1 = x1;
    clip_x2 = x2;
    clip_y1 = y1;
    clip_y2 = y2;
}

unsigned long DBPoint(unsigned short x, unsigned short y)
{
    return(*(unsigned long *)&DblBuffer[((unsigned long)y << 10) + ((unsigned long)y << 8) + ((unsigned long)x << 2)]);
}

/*void DBPSet(unsigned short x, unsigned short y, unsigned long c)
{
    *(unsigned long *)&DblBuffer[((unsigned long)y << 10) + ((unsigned long)y << 8) + ((unsigned long)x << 2)] = c;
}*/

void DBPSetC(unsigned short x, unsigned short y, unsigned long c)
{
    if ((x >= clip_x1) && (x <= clip_x2) && (y >= clip_y1) && (y <= clip_y2))
        *(unsigned long *)&DblBuffer[((unsigned long)y << 10) + ((unsigned long)y << 8) + ((unsigned long)x << 2)] = c;
}

void DBPSetCTrans(unsigned short x, unsigned short y, unsigned long c, unsigned char Method)
{
    if ((x >= clip_x1) && (x <= clip_x2) && (y >= clip_y1) && (y <= clip_y2))
        TransOps[Method]((unsigned long *)&DblBuffer[((unsigned long)y << 10) + ((unsigned long)y << 8) + ((unsigned long)x << 2)], c);
}

void DBFRect(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2, unsigned long c)
{
    unsigned short y, x;

    for(y = y1; y <= y2; y++)
    {
        for(x = x1; x <= x2; x++)
        {
            DBPSetC(x, y, c);
        }
    }
}

void DBFRectTrans(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2, unsigned long c, unsigned char Method)
{
    unsigned short y, x;

    for(y = y1; y <= y2; y++)
    {
        for(x = x1; x <= x2; x++)
        {
            DBPSetCTrans(x, y, c, Method);
        }
    }
}

void DBFCircle(signed short x, signed short y, unsigned short r, unsigned long Color, unsigned char Filled, float Aspect)
{
    signed short y1, y2, x1, x2;
    signed short cy, cx;
    unsigned long r2;

    if(y - r < clip_y1)
    {
        y1 = clip_y1;
        cy = clip_y1 - y;
    } else {
        y1 = y - r;
        cy = -r;
    }
    if(y + r > clip_y2)
        y2 = clip_y2 - y;
    else
        y2 = r;
    for(r2 = (unsigned long)r * (unsigned long)r; cy <= y2; cy++)
    {
        x1 = x - (x2 = (sqrt(r2 - ((unsigned long)cy * (unsigned long)cy)) * Aspect));
        x2 += x;
        if(Filled == 1)
        {
            if(x1 < clip_x1)
                x1 = clip_x1;
            if(x2 > clip_x2)
                x2 = clip_x2;
            for(cx = x1; cx <= x2; cx++)
                DBPSetC(cx, y1, Color);
        } else {
            DBPSetC(x1, y1, Color);
            DBPSetC(x2, y1, Color);
        }
        y1++;
    }
}

void DBFCircleTrans(signed short x, signed short y, unsigned short r, unsigned long Color, unsigned char Filled, float Aspect, unsigned char Method)
{
    signed short y1, y2, x1, x2;
    signed short cy, cx;
    unsigned long r2;

    if(y - r < clip_y1)
    {
        y1 = clip_y1;
        cy = clip_y1 - y;
    } else {
        y1 = y - r;
        cy = -r;
    }
    if(y + r > clip_y2)
        y2 = clip_y2 - y;
    else
        y2 = r;
    for(r2 = (unsigned long)r * (unsigned long)r; cy <= y2; cy++)
    {
        x1 = x - (x2 = (sqrt(r2 - ((unsigned long)cy * (unsigned long)cy)) * Aspect));
        x2 += x;
        if(Filled == 1)
        {
            if(x1 < clip_x1)
                x1 = clip_x1;
            if(x2 > clip_x2)
                x2 = clip_x2;
            for(cx = x1; cx <= x2; cx++)
                DBPSetCTrans(cx, y1, Color, Method);
        } else {
            DBPSetCTrans(x1, y1, Color, Method);
            DBPSetCTrans(x2, y1, Color, Method);
        }
        y1++;
    }
}

void DBFCircleFadedTrans(signed short x, signed short y, unsigned short r, unsigned long Color, float Aspect, unsigned char Method)
{
    signed short y1, y2, x1, x2;
    signed short cy, cx;
    unsigned long r2;
    struct ColorType MainColor, MidColor, CurColor;
    unsigned short RE, GE, BE;
    signed char Inc;

    if(y - r < clip_y1)
    {
        y1 = clip_y1;
        cy = clip_y1 - y;
    } else {
        y1 = y - r;
        cy = -r;
    }
    if(y + r > clip_y2)
        y2 = clip_y2 - y;
    else
        y2 = r;
    MainColor = *(struct ColorType *)&Color;
    for(r2 = (unsigned long)r * (unsigned long)r; cy <= y2; cy++)
    {
        if(cy < 0)
        {
            MidColor.R = (unsigned char)(((unsigned long)MainColor.R * (unsigned long)(r + cy)) / (unsigned long)r);
            MidColor.G = (unsigned char)(((unsigned long)MainColor.G * (unsigned long)(r + cy)) / (unsigned long)r);
            MidColor.B = (unsigned char)(((unsigned long)MainColor.B * (unsigned long)(r + cy)) / (unsigned long)r);
        } else {
            MidColor.R = (unsigned char)(((unsigned long)MainColor.R * (unsigned long)(r - cy)) / (unsigned long)r);
            MidColor.G = (unsigned char)(((unsigned long)MainColor.G * (unsigned long)(r - cy)) / (unsigned long)r);
            MidColor.B = (unsigned char)(((unsigned long)MainColor.B * (unsigned long)(r - cy)) / (unsigned long)r);
        }
        *(unsigned long *)&CurColor = 0;
        RE = GE = BE = 0;
        x1 = x - (x2 = (sqrt(r2 - ((unsigned long)cy * (unsigned long)cy)) * Aspect));
        x2 += x;
        Inc = 1;
        if(x1 < clip_x1)
        {
            CurColor.R = (unsigned char)(((unsigned long)(clip_x1 - x1) * (unsigned long)MidColor.R) / (unsigned long)r);
            CurColor.G = (unsigned char)(((unsigned long)(clip_x1 - x1) * (unsigned long)MidColor.G) / (unsigned long)r);
            CurColor.B = (unsigned char)(((unsigned long)(clip_x1 - x1) * (unsigned long)MidColor.B) / (unsigned long)r);
            x1 = clip_x1;
            if(x1 > x)
                Inc = -1;
        }
        if(x2 > clip_x2)
            x2 = clip_x2;
        for(cx = x1; cx <= x2; cx++)
        {
            if(cx == x)
            {
                Inc = -1;
                RE = GE = BE = 0;
            }
            DBPSetCTrans(cx, y1, *(unsigned long *)&CurColor, Method);
            RE += (unsigned short)MidColor.R;
            GE += (unsigned short)MidColor.G;
            BE += (unsigned short)MidColor.B;
            while(RE > r)
            {
                RE -= r;
                CurColor.R += Inc;
            }
            while(GE > r)
            {
                GE -= r;
                CurColor.G += Inc;
            }
            while(BE > r)
            {
                BE -= r;
                CurColor.B += Inc;
            }
        }
        y1++;
    }
}

void DBFPoly(signed short x1, signed short y1, signed short x2, signed short y2, signed short x3, signed short y3, unsigned long Color)
{
    signed short x[3], y[3], Temp, m1, m2;
    signed short i, o, StartX, StopX;
    signed long k1, k2, cx1, cx2;

    x[0] = x1; y[0] = y1;
    x[1] = x2; y[1] = y2;
    x[2] = x3; y[2] = y3;
    for(i = 0; i < 2; i++)
    {
        for(o = i + 1; o < 3; o++)
        {
            if(y[o] < y[i])
            {
                Temp = y[o];
                y[o] = y[i];
                y[i] = Temp;
                Temp = x[o];
                x[o] = x[i];
                x[i] = Temp;
            }
        }
    }
    cx1 = cx2 = x[0] << 16;
    if(y[0] == y[1])
    {
        cx1 = x[1] << 16;
    } else {
        k1 = ((signed long)(x[1] - x[0]) << 16) / (signed long)(y[1] - y[0]);
        k2 = ((signed long)(x[2] - x[0]) << 16) / (signed long)(y[2] - y[0]);
        for(i = y[0]; i <= y[1]; i++)
        {
            if((i >= clip_y1) && (i <= clip_y2))
            {
                if(cx1 > cx2)
                {
                    StartX = cx2 >> 16;
                    StopX = cx1 >> 16;
                } else {
                    StartX = cx1 >> 16;
                    StopX = cx2 >> 16;
                }
                if(StartX < clip_x1)
                    StartX = clip_x1;
                if(StopX > clip_x2)
                    StopX = clip_x2;
                if((StartX <= clip_x2) && (StopX >= clip_x1))
                {
                    for(o = StartX; o <= StopX; o++)
                        DBPSetC(o, i, Color);
                }
            }
            /*asm("
            cld
            rep stosl
            "
            :
            : "a" (Color), "c" ((abs(x1 - x2) >> 16) + 1), "D" ((unsigned long)DblBuffer + ((unsigned long)i << 10) + ((unsigned long)i << 8) + (((x1 < x2)?x1:x2) >> 14))
            );*/
            cx1 += k1;
            cx2 += k2;
        }
    }
    if(y[1] == y[2])
        return;
    k1 = ((signed long)(x[2] - x[1]) << 16) / (signed long)(y[2] - y[1]);
    k2 = ((signed long)(x[2] - x[0]) << 16) / (signed long)(y[2] - y[0]);
    for(i = y[1] + 1; i <= y[2]; i++)
    {
        if((i >= clip_y1) && (i <= clip_y2))
        {
            if(cx1 > cx2)
            {
                StartX = cx2 >> 16;
                StopX = cx1 >> 16;
            } else {
                StartX = cx1 >> 16;
                StopX = cx2 >> 16;
            }
            if(StartX < clip_x1)
                StartX = clip_x1;
            if(StopX > clip_x2)
                StopX = clip_x2;
            if((StartX <= clip_x2) && (StopX >= clip_x1))
            {
                for(o = StartX; o <= StopX; o++)
                    DBPSetC(o, i, Color);
            }
        }
        /*asm("
        cld
        rep stosl
        "
        :
        : "a" (Color), "c" ((abs(x1 - x2) >> 16) + 1), "D" ((unsigned long)DblBuffer + ((unsigned long)i << 10) + ((unsigned long)i << 8) + (((x1 < x2)?x1:x2) >> 14))
        );*/
        cx1 += k1;
        cx2 += k2;
    }
}

void DBFPolyTrans(signed short x1, signed short y1, signed short x2, signed short y2, signed short x3, signed short y3, unsigned long Color, unsigned char Method)
{
    signed short x[3], y[3], Temp, m1, m2;
    signed short i, o, StartX, StopX;
    signed long k1, k2, cx1, cx2;

    x[0] = x1; y[0] = y1;
    x[1] = x2; y[1] = y2;
    x[2] = x3; y[2] = y3;
    for(i = 0; i < 2; i++)
    {
        for(o = i + 1; o < 3; o++)
        {
            if(y[o] < y[i])
            {
                Temp = y[o];
                y[o] = y[i];
                y[i] = Temp;
                Temp = x[o];
                x[o] = x[i];
                x[i] = Temp;
            }
        }
    }
    cx1 = cx2 = x[0] << 16;
    if(y[0] == y[1])
    {
        cx1 = x[1] << 16;
    } else {
        k1 = ((signed long)(x[1] - x[0]) << 16) / (signed long)(y[1] - y[0]);
        k2 = ((signed long)(x[2] - x[0]) << 16) / (signed long)(y[2] - y[0]);
        for(i = y[0]; i <= y[1]; i++)
        {
            if((i >= clip_y1) && (i <= clip_y2))
            {
                if(cx1 > cx2)
                {
                    StartX = cx2 >> 16;
                    StopX = cx1 >> 16;
                } else {
                    StartX = cx1 >> 16;
                    StopX = cx2 >> 16;
                }
                if(StartX < clip_x1)
                    StartX = clip_x1;
                if(StopX > clip_x2)
                    StopX = clip_x2;
                if((StartX <= clip_x2) && (StopX >= clip_x1))
                {
                    for(o = StartX; o <= StopX; o++)
                        DBPSetCTrans(o, i, Color, Method);
                }
            }
            cx1 += k1;
            cx2 += k2;
        }
        cx1 -= k1;
        cx2 -= k2;
    }
    if(y[1] == y[2])
        return;
    k1 = ((signed long)(x[2] - x[1]) << 16) / (signed long)(y[2] - y[1]);
    k2 = ((signed long)(x[2] - x[0]) << 16) / (signed long)(y[2] - y[0]);
    for(i = y[1] + 1; i <= y[2]; i++)
    {
        if((i >= clip_y1) && (i <= clip_y2))
        {
            if(cx1 > cx2)
            {
                StartX = cx2 >> 16;
                StopX = cx1 >> 16;
            } else {
                StartX = cx1 >> 16;
                StopX = cx2 >> 16;
            }
            if(StartX < clip_x1)
                StartX = clip_x1;
            if(StopX > clip_x2)
                StopX = clip_x2;
            if((StartX <= clip_x2) && (StopX >= clip_x1))
            {
                for(o = StartX; o <= StopX; o++)
                    DBPSetCTrans(o, i, Color, Method);
            }
        }
        cx1 += k1;
        cx2 += k2;
    }
}

void DBLine(signed short x1, signed short y1, signed short x2, signed short y2, unsigned long c1, unsigned long c2)
{
    signed short dx, dy, x, y;
    signed short xi, yi, d;
    unsigned short i;
    unsigned char c;

    dx = x2 - x1;
    dy = y2 - y1;
    if(dx >= 0)
    {
        xi = 1;
    } else {
        xi = -1;
        dx = -dx;
    }
    if(dy >= 0)
    {
        yi = 1;
    } else {
        yi = -1;
        dy = -dy;
    }
    d = 0;
    x = x1;
    y = y1;
    c = 0;
    if(dx > dy)
    {
        for(i = 0; i <= dx; i++)
        {
            DBPSetC((unsigned short)x, (unsigned short)y, ((c ^= 1) == 0)?c2:c1);
            d += dy;
            if(d > dx)
            {
                d -= dx;
                y += yi;
            }
            x += xi;
        }
    } else {
        for(i = 0; i <= dy; i++)
        {
            DBPSetC((unsigned short)x, (unsigned short)y, ((c ^= 1) == 0)?c2:c1);
            d += dx;
            if(d > 0)
            {
                d -= dy;
                x += xi;
            }
            y += yi;
        }
    }
}

void DBLineTrans(signed short x1, signed short y1, signed short x2, signed short y2, unsigned long c1, unsigned long c2, unsigned char Method)
{
    signed short dx, dy, x, y;
    signed short xi, yi, d;
    unsigned short i;
    unsigned char c;

    dx = x2 - x1;
    dy = y2 - y1;
    if(dx >= 0)
    {
        xi = 1;
    } else {
        xi = -1;
        dx = -dx;
    }
    if(dy >= 0)
    {
        yi = 1;
    } else {
        yi = -1;
        dy = -dy;
    }
    d = 0;
    x = x1;
    y = y1;
    c = 0;
    if(dx > dy)
    {
        for(i = 0; i <= dx; i++)
        {
            DBPSetCTrans((unsigned short)x, (unsigned short)y, ((c ^= 1) == 0)?c2:c1, Method);
            d += dy;
            if(d > dx)
            {
                d -= dx;
                y += yi;
            }
            x += xi;
        }
    } else {
        for(i = 0; i <= dy; i++)
        {
            DBPSetCTrans((unsigned short)x, (unsigned short)y, ((c ^= 1) == 0)?c2:c1, Method);
            d += dx;
            if(d > 0)
            {
                d -= dy;
                x += xi;
            }
            y += yi;
        }
    }
}

void DBCopyBuffer(signed short x, signed short y, unsigned char *Buffer, unsigned short w, unsigned short h, unsigned long bgc)
{
    unsigned char *WorkOffset;
    unsigned long offset;
    unsigned long OffsetAdd;
    unsigned short cx, cy;
    unsigned long data;

    offset = 0;
    WorkOffset = DblBuffer + ((signed long)y << 10) + ((signed long)y << 8) + ((signed long)x << 2);
    OffsetAdd = 1280 - (w << 2);
    for(cy = 0; cy < h; cy++)
    {
        for(cx = 0; cx < w; cx++)
        {
            data = *(unsigned long *)Buffer;
            if(data != bgc)
                *(unsigned long *)WorkOffset = data;
            Buffer += 4;
            WorkOffset += 4;
        }
        WorkOffset += OffsetAdd;
    }
/*
    DBCopyBufferAsm(x, y, Buffer, w, h, bgc);
*/
}

void DBCopyBufferClip(signed short x, signed short y, unsigned char *Buffer, unsigned short w, unsigned short h, unsigned long bgc)
{
    unsigned char *WorkOffset;
    unsigned long OffsetAdd1, OffsetAdd2;
    signed short cx, cy, sx, sy, cw, ch;
    unsigned long data;

    if((x > clip_x2) || ((x + w) < clip_x1) || (y > clip_y2) || ((y + h) < clip_y1))
        return;
    if((x >= clip_x1) && ((x + w) <= clip_x2) && (y >= clip_y1) && ((y + h) <= clip_y2))
    {
        DBCopyBuffer(x, y, Buffer, w, h, bgc);
        return;
    }
    sx = (x < clip_x1)?(clip_x1 - x):0;
    sy = (y < clip_y1)?(clip_y1 - y):0;
    cw = (x + (signed short)w - 1 > clip_x2)?(clip_x2 - x + 1):(signed short)w;
    ch = (y + (signed short)h - 1 > clip_y2)?(clip_y2 - y + 1):(signed short)h;
    Buffer += (sx + (sy * w)) << 2;
    OffsetAdd1 = (sx + w - cw) << 2;
    OffsetAdd2 = 1280 - ((cw - sx) << 2);
    WorkOffset = DblBuffer + ((signed long)(y + sy) << 10) + ((signed long)(y + sy) << 8) + ((signed long)(x + sx) << 2);
    for(cy = 0; cy < ch - sy; cy++)
    {
        for(cx = 0; cx < cw - sx; cx++)
        {
            data = *(unsigned long *)Buffer;
            if(data != bgc)
                *(unsigned long *)WorkOffset = data;
            Buffer += 4;
            WorkOffset += 4;
        }
        Buffer += OffsetAdd1;
        WorkOffset += OffsetAdd2;
    }
}

void DBSpriteLine(signed short x1, signed short y1, signed short x2, signed short y2, unsigned char *Buffer, unsigned short w, unsigned short h)
{
    signed short dx, dy, x, y;
    signed short xi, yi, d;
    unsigned short i;
    unsigned char c;

    dx = x2 - x1;
    dy = y2 - y1;
    if(dx >= 0)
    {
        xi = 1;
    } else {
        xi = -1;
        dx = -dx;
    }
    if(dy >= 0)
    {
        yi = 1;
    } else {
        yi = -1;
        dy = -dy;
    }
    d = 0;
    x = x1;
    y = y1;
    c = 0;
    if(dx > dy)
    {
        for(i = 0; i <= dx; i++)
        {
            DBCopyBufferClip((unsigned short)x, (unsigned short)y, Buffer, w, h, 0);
            d += dy;
            if(d > dx)
            {
                d -= dx;
                y += yi;
            }
            x += xi;
        }
    } else {
        for(i = 0; i <= dy; i++)
        {
            DBCopyBufferClip((unsigned short)x, (unsigned short)y, Buffer, w, h, 0);
            d += dx;
            if(d > 0)
            {
                d -= dy;
                x += xi;
            }
            y += yi;
        }
    }
}

void DBCopyBufferRotated(signed short x, signed short y, unsigned char *Buffer, unsigned short w, unsigned short h, unsigned long bgc, signed short rx, signed short ry, unsigned short a)
{
    signed short cx, cy, sx, sy, xd, yd;
    unsigned long Data, OffsetMax;
    signed long w1, h1;
    signed long x0, y0, xn, yn;
    signed long c, s;

    c = (signed long)(Cosine[a] * 0x10000);
    s = (signed long)(Sine[a] * 0x10000);
    if(a < 90)
    {
        w1 = (s * h) + (c * w);
        h1 = (c * h) + (s * w);
        x0 = (signed long)((Sine[a] * Sine[a] * (float)w) * 0x10000);
        y0 = (signed long)(-(Sine[a] * Cosine[a] * (float)w) * 0x10000);
        xd = 0;
        yd = (signed short)((s * (signed long)w) >> 16);
    } else if(a < 180)
    {
        w1 = (s * h) - (c * w);
        h1 = (s * w) - (c * h);
        x0 = (signed long)((w - ((Sine[a] * Cosine[a]) * (float)h)) * 0x10000);
        y0 = (signed long)((Cosine[a] * Cosine[a] * (float)h) * 0x10000);
        xd = (signed short)((-c * (signed long)w) >> 16);
        yd = (signed short)(h1 >> 16);
    } else if(a < 270)
    {
        w1 = -(s * h) - (c * w);
        h1 = -(s * w) - (c * h);
        x0 = (signed long)((Cosine[a] * Cosine[a] * (float)w) * 0x10000);
        y0 = (signed long)((h + (Sine[a] * Cosine[a] * (float)w)) * 0x10000);
        xd = (signed short)(w1 >> 16);
        yd = (signed short)((-c * (signed long)h) >> 16);
    } else {
        w1 = (c * w) - (s * h);
        h1 = (c * h) - (s * w);
        x0 = (signed long)((Sine[a] * Cosine[a] * (float)h) * 0x10000);
        y0 = (signed long)((Sine[a] * Sine[a] * (float)h) * 0x10000);
        xd = (signed short)((-s * (signed long)h) >> 16);
        yd = 0;
    }
    if((w1 & 0xFFFF) != 0)
        w1 = (w1 & 0xFFFF0000) + 0x10000;
    if((h1 & 0xFFFF) != 0)
        h1 = (h1 & 0xFFFF0000) + 0x10000;
    w1 >>= 16;
    h1 >>= 16;
    xd += (signed short)(((c * (signed long)rx) + (s * (signed long)ry)) >> 16);
    yd += (signed short)(((c * (signed long)ry) - (s * (signed long)ry)) >> 16);
    sy = y - yd;
    for(cy = 0; cy < h1; cy++)
    {
        xn = x0;
        yn = y0;
        sx = x - xd;
        for(cx = 0; cx < w1; cx++)
        {
            if((xn >= 0) && (yn >= 0) && (xn < (w << 16)) && (yn < (h << 16)))
            {
                Data = ((unsigned long *)Buffer)[((xn & 0xFFFF0000) + ((yn & 0xFFFF0000) * w)) >> 16];
                if(Data != bgc)
                    DBPSetC(sx, sy, Data);
                if((sx == x) && (sy == y))
                    ((unsigned long *)Buffer)[((xn & 0xFFFF0000) + ((yn & 0xFFFF0000) * w)) >> 16] = MakeColor(255, 0, 0);
            }
            sx++;
            xn += c;
            yn += s;
        }
        x0 -= s;
        y0 += c;
        sy++;
    }
}

void ColorAdd(unsigned long *Bg, unsigned long Amount)
{
    Color *c1;
    Color c2;
    unsigned short R, G, B;

    c1 = (Color *)Bg;
    c2 = *(Color *)&Amount;
    R = (unsigned short)c1->R + (unsigned short)c2.R;
    G = (unsigned short)c1->G + (unsigned short)c2.G;
    B = (unsigned short)c1->B + (unsigned short)c2.B;
    if(R > 255)
        R = 255;
    if(G > 255)
        G = 255;
    if(B > 255)
        B = 255;
    c1->R = (unsigned char)R;
    c1->G = (unsigned char)G;
    c1->B = (unsigned char)B;
}

void ColorSub(unsigned long *Bg, unsigned long Amount)
{
    Color *c1;
    Color c2;
    signed short R, G, B;

    c1 = (Color *)Bg;
    c2 = *(Color *)&Amount;
    R = (unsigned short)c1->R - (unsigned short)c2.R;
    G = (unsigned short)c1->G - (unsigned short)c2.G;
    B = (unsigned short)c1->B - (unsigned short)c2.B;
    if(R < 0)
        R = 0;
    if(G < 0)
        G = 0;
    if(B < 0)
        B = 0;
    c1->R = (unsigned char)R;
    c1->G = (unsigned char)G;
    c1->B = (unsigned char)B;
}

/*void ColorAdd(unsigned long *Bg, unsigned long Amount)
{
    asm("
    movd %%eax, %%mm0
    movd (%%esi), %%mm1
    paddusb %%mm1, %%mm0
    movd %%mm0, 0(%%esi)
    "
    :
    : "a" (Amount), "S" (Bg)
    );
    asm("
    addb %%al, 0(%%esi)
    jnc ColorAddNoBlueOF
    movb $0xFF, 0(%%esi)
ColorAddNoBlueOF:
    addb %%ah, 1(%%esi)
    jnc ColorAddNoGreenOF
    movb $0xFF, 1(%%esi)
ColorAddNoGreenOF:
    shrl $0x10, %%eax
    addb %%al, 2(%%esi)
    jnc ColorAddNoRedOF
    movb $0xFF, 2(%%esi)
ColorAddNoRedOF:
    "
    :
    : "a" (Amount), "S" (Bg)
    );
}*/

/*void ColorSub(unsigned long *Bg, unsigned long Amount)
{
    asm("
    subb %%al, 0(%%esi)
    jnc ColorSubNoBlueOF
    movb $0x00, 0(%%esi)
ColorSubNoBlueOF:
    subb %%ah, 1(%%esi)
    jnc ColorSubNoGreenOF
    movb $0x00, 1(%%esi)
ColorSubNoGreenOF:
    shrl $0x10, %%eax
    subb %%al, 2(%%esi)
    jnc ColorSubNoRedOF
    movb $0x00, 2(%%esi)
ColorSubNoRedOF:
    "
    :
    : "a" (Amount), "S" (Bg)
    );
}*/

void ColorAvr(unsigned long *Bg, unsigned long Amount)
{
/*
    asm("
    addb %%al, 0(%%esi)
    .byte 0xD0
    .byte 0x1E
    addb %%ah, 1(%%esi)
    .byte 0xD0
    .byte 0x5E
    .byte 1
    shrl $0x10, %%eax
    addb %%al, 2(%%esi)
    .byte 0xD0
    .byte 0x5E
    .byte 2
    "
    :
    : "a" (Amount), "S" (Bg)
    );
*/
    ((Color *)(Bg))->R = (unsigned char)(((unsigned short)((Color *)(Bg))->R + (unsigned short)(*(Color *)(&Amount)).R) >> 1);
    ((Color *)(Bg))->G = (unsigned char)(((unsigned short)((Color *)(Bg))->G + (unsigned short)(*(Color *)(&Amount)).G) >> 1);
    ((Color *)(Bg))->B = (unsigned char)(((unsigned short)((Color *)(Bg))->B + (unsigned short)(*(Color *)(&Amount)).B) >> 1);
}

void ColorSpc(unsigned long *Bg, unsigned long Amount)
{
    Color *c1;
    Color c2;
    unsigned short R, G, B;

    c1 = (Color *)Bg;
    c2 = *(Color *)&Amount;
    R = ((3 * (unsigned short)c1->R) + (3 * (unsigned short)c2.R)) >> 2;
    G = ((3 * (unsigned short)c1->G) + (3 * (unsigned short)c2.G)) >> 2;
    B = ((3 * (unsigned short)c1->B) + (3 * (unsigned short)c2.B)) >> 2;
    if(R > 255)
        R = 255;
    if(G > 255)
        G = 255;
    if(B > 255)
        B = 255;
    c1->R = (unsigned char)R;
    c1->G = (unsigned char)G;
    c1->B = (unsigned char)B;
}

void ColorFul(unsigned long *Bg, unsigned long Amount)
{
    Color *c1, c2;

    *(unsigned long *)&c2 = Amount;
    c1 = (Color *)Bg;
    if(c2.R > c1->R)
        c1->R = c2.R;
    if(c2.G > c1->G)
        c1->G = c2.G;
    if(c2.B > c1->B)
        c1->B = c2.B;
}

void DBCopyMapBufferClip(signed short x, signed short y, unsigned char *Buffer, unsigned char *BgBuffer, unsigned short w, unsigned short h)
{
    unsigned char *WorkOffset;
    unsigned long OffsetAdd1, OffsetAdd2;
    signed short cx, cy, sx, sy, cw, ch;
    unsigned long data;

    if((x > clip_x2) || ((x + w) < clip_x1) || (y > clip_y2) || ((y + h) < clip_y1))
        return;
    sx = (x < clip_x1)?(clip_x1 - x):0;
    sy = (y < clip_y1)?(clip_y1 - y):0;
    cw = (x + (signed short)w - 1 > clip_x2)?(clip_x2 - x + 1):(signed short)w;
    ch = (y + (signed short)h - 1 > clip_y2)?(clip_y2 - y + 1):(signed short)h;
    Buffer += (sx + (sy * w)) << 2;
    BgBuffer += sx + (sy * w);
    OffsetAdd1 = (sx + w - cw) << 2;
    OffsetAdd2 = 1280 - ((cw - sx) << 2);
    WorkOffset = DblBuffer + ((signed long)(y + sy) << 10) + ((signed long)(y + sy) << 8) + ((signed long)(x + sx) << 2);
    for(cy = 0; cy < ch - sy; cy++)
    {
        for(cx = 0; cx < cw - sx; cx++)
        {
            data = *(unsigned long *)Buffer;
            if(data != 0)
            {
                if(((*BgBuffer) & 0x70) == 0x20)
                    ColorAdd((unsigned long *)WorkOffset, data);
                else
                    *(unsigned long *)WorkOffset = data;
            }
            Buffer += 4;
            BgBuffer++;
            WorkOffset += 4;
        }
        Buffer += OffsetAdd1;
        BgBuffer += OffsetAdd1 >> 2;
        WorkOffset += OffsetAdd2;
    }
}

void DBCopyBufferTrans(signed short x, signed short y, unsigned char *Buffer, unsigned short w, unsigned short h, unsigned long bgc, unsigned char Method)
{
    unsigned char *WorkOffset;
    unsigned long OffsetAdd;
    unsigned short cx, cy;
    unsigned long data;

    WorkOffset = DblBuffer + ((signed long)y << 10) + ((signed long)y << 8) + ((signed long)x << 2);
    OffsetAdd = 1280 - (w << 2);
    for(cy = 0; cy < h; cy++)
    {
        for(cx = 0; cx < w; cx++)
        {
            data = *(unsigned long *)Buffer;
            if(data != bgc)
                TransOps[Method]((unsigned long *)WorkOffset, data);
            Buffer += 4;
            WorkOffset += 4;
        }
        WorkOffset += OffsetAdd;
    }
}

void DBCopyBufferClipTrans(signed short x, signed short y, unsigned char *Buffer, unsigned short w, unsigned short h, unsigned short bgc, unsigned char Method)
{
    unsigned char *WorkOffset;
    unsigned long OffsetAdd1, OffsetAdd2;
    signed short cx, cy, sx, sy, cw, ch;
    unsigned long data;

    if((x > clip_x2) || ((x + w) < clip_x1) || (y > clip_y2) || ((y + h) < clip_y1))
        return;
    if((x >= clip_x1) && ((x + w) <= clip_x2) && (y >= clip_y1) && ((y + h) <= clip_y2))
    {
        DBCopyBufferTrans(x, y, Buffer, w, h, bgc, Method);
        return;
    }
    sx = (x < clip_x1)?(clip_x1 - x):0;
    sy = (y < clip_y1)?(clip_y1 - y):0;
    cw = (x + (signed short)w - 1 > clip_x2)?(clip_x2 - x + 1):(signed short)w;
    ch = (y + (signed short)h - 1 > clip_y2)?(clip_y2 - y + 1):(signed short)h;
    Buffer += (sx + (sy * w)) << 2;
    OffsetAdd1 = (sx + w - cw) << 2;
    OffsetAdd2 = 1280 - ((cw - sx) << 2);
    WorkOffset = DblBuffer + ((signed long)(y + sy) << 10) + ((signed long)(y + sy) << 8) + ((signed long)(x + sx) << 2);
    for(cy = 0; cy < ch - sy; cy++)
    {
        for(cx = 0; cx < cw - sx; cx++)
        {
            data = *(unsigned long *)Buffer;
            if(data != bgc)
                TransOps[Method]((unsigned long *)WorkOffset, data);
            Buffer += 4;
            WorkOffset += 4;
        }
        Buffer += OffsetAdd1;
        WorkOffset += OffsetAdd2;
    }
}

void DBSpriteLineTrans(signed short x1, signed short y1, signed short x2, signed short y2, unsigned char *Buffer, unsigned short w, unsigned short h, unsigned char Method)
{
    signed short dx, dy, x, y;
    signed short xi, yi, d;
    unsigned short i;
    unsigned char c;

    dx = x2 - x1;
    dy = y2 - y1;
    if(dx >= 0)
    {
        xi = 1;
    } else {
        xi = -1;
        dx = -dx;
    }
    if(dy >= 0)
    {
        yi = 1;
    } else {
        yi = -1;
        dy = -dy;
    }
    d = 0;
    x = x1;
    y = y1;
    c = 0;
    if(dx > dy)
    {
        for(i = 0; i <= dx; i++)
        {
            DBCopyBufferClipTrans((unsigned short)x, (unsigned short)y, Buffer, w, h, 0, Method);
            d += dy;
            if(d > dx)
            {
                d -= dx;
                y += yi;
            }
            x += xi;
        }
    } else {
        for(i = 0; i <= dy; i++)
        {
            DBCopyBufferClipTrans((unsigned short)x, (unsigned short)y, Buffer, w, h, 0, Method);
            d += dx;
            if(d > 0)
            {
                d -= dy;
                x += xi;
            }
            y += yi;
        }
    }
}

void DBCopyBufferTransRotated(signed short x, signed short y, unsigned char *Buffer, unsigned short w, unsigned short h, unsigned long bgc, unsigned char Method, signed short rx, signed short ry, unsigned short a)
{
    unsigned short cx, cy, sx, sy;
    unsigned long Data, OffsetMax;
    signed long w1, h1;
    signed long x0, y0, xn, yn;
    signed long c, s;

    c = (signed long)(Cosine[a] * 0x10000);
    s = (signed long)(Sine[a] * 0x10000);
    w1 = (s * h) + (c * w);
    h1 = (c * h) + (s * w);
    x0 = (signed long)((Sine[a] * Sine[a] * (float)w) * 0x10000);
    y0 = (signed long)(-(Sine[a] * Cosine[a] * (float)w) * 0x10000);
    if((w1 & 0xFFFF) != 0)
        w1 = (w1 & 0xFFFF0000) + 0x10000;
    if((h1 & 0xFFFF) != 0)
        h1 = (h1 & 0xFFFF0000) + 0x10000;
    w1 >>= 16;
    h1 >>= 16;
    sx = x;
    sy = y;
    for(cy = 0; cy < h1; cy++)
    {
        xn = x0;
        yn = y0;
        for(cx = 0; cx < w1; cx++)
        {
            if((xn >= 0) && (yn >= 0) && (xn < (w << 16)) && (yn < (h << 16)))
            {
                Data = ((unsigned long *)Buffer)[((xn & 0xFFFF0000) + ((yn & 0xFFFF0000) * w)) >> 16];
                if(Data != bgc)
                    DBPSetCTrans(sx, sy, Data, Method);
            }
            sx++;
            xn += c;
            yn += s;
        }
        x0 -= s;
        y0 += c;
        sy++;
        sx = x;
    }
}

#undef MOTION_BLUR

void DisplayDB(void)
{
    SDL_Flip(VBuffer);
}

#if 0
void DisplayDB(void)
{
    unsigned long i;

#ifdef DEBUG
    return;
#endif
#ifndef MOTION_BLUR
    if(BPP == 0x20)
    {
        /*for(i = 0; i < 256000; i += 4)
        {
            *(unsigned long *)&VBuffer[i] = SmoothColor(*(unsigned long *)&DblBuffer[i], *(unsigned long *)&DblBuffer[i - 1280], *(unsigned long *)&DblBuffer[i + 1280], *(unsigned long *)&DblBuffer[i - 4], *(unsigned long *)&DblBuffer[i + 4]);
        }*/
        /*for(i = 0; i < 64000; i++)
            ((unsigned long *)VBuffer)[i] = ((unsigned long *)DblBuffer)[i];*/
        DisplayDBAsm();
        /*for(i = 0; i < 256000; i++)
            _farpokeb(VideoLDT, i, DblBuffer[i]);*/
    } else {
        for(i = 0; i < 64000; i++)
        {
            VBuffer[i * 3] = (DblBuffer)[i * 4];
            VBuffer[(i * 3) + 1] = (DblBuffer)[(i * 4) + 1];
            VBuffer[(i * 3) + 2] = (DblBuffer)[(i * 4) + 2];
        }
    }
#else
    asm("
    mov $0, %%eax
    movd %%eax, %%mm2
    "
    :
    :
    : "%eax"
    );
    for(i = 0; i < 256000; i += 4)
    {
        asm("
        movd (%%eax), %%mm0
        movd (%%esi), %%mm1
        punpcklbw %%mm2, %%mm0
        punpcklbw %%mm2, %%mm1
        paddw %%mm1, %%mm0
        psrlw $1, %%mm0
        packuswb %%mm0, %%mm0
        movd %%mm0, (%%esi)
        "
        :
        : "a" (DblBuffer + i), "S" (VBuffer + i)
        );
    }
    asm("emms");
#endif
}
#endif
