#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "osdepend.h"
#include "blit.h"
#include "win32.h"
#include "video.h"
#include "misc.h"

/****************************************************************************
    External valiable
 ***************************************************************************/

DWORD brightmask[2];

/****************************************************************************
    Prototypes
 ***************************************************************************/

#define BLITER(srcbpp, dstbpp, mmx)                                                     \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_1x1_sl0_bl0_mmx##mmx##(BLITERARGS);  \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_1x2_sl0_bl0_mmx##mmx##(BLITERARGS);  \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_1x2_sl1_bl0_mmx##mmx##(BLITERARGS);  \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_1x2_sl1_bl25_mmx##mmx##(BLITERARGS); \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_1x2_sl1_bl50_mmx##mmx##(BLITERARGS); \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_1x2_sl1_bl75_mmx##mmx##(BLITERARGS); \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x1_sl0_bl0_mmx##mmx##(BLITERARGS);  \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x1_sl2_bl0_mmx##mmx##(BLITERARGS);  \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x1_sl2_bl25_mmx##mmx##(BLITERARGS); \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x1_sl2_bl50_mmx##mmx##(BLITERARGS); \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x1_sl2_bl75_mmx##mmx##(BLITERARGS); \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x2_sl0_bl0_mmx##mmx##(BLITERARGS);  \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x2_sl1_bl0_mmx##mmx##(BLITERARGS);  \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x2_sl1_bl25_mmx##mmx##(BLITERARGS); \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x2_sl1_bl50_mmx##mmx##(BLITERARGS); \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x2_sl1_bl75_mmx##mmx##(BLITERARGS); \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x2_sl2_bl0_mmx##mmx##(BLITERARGS);  \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x2_sl2_bl25_mmx##mmx##(BLITERARGS); \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x2_sl2_bl50_mmx##mmx##(BLITERARGS); \
extern void __cdecl asmblit_##srcbpp##to##dstbpp##_2x2_sl2_bl75_mmx##mmx##(BLITERARGS); \

BLITER(16, 16, 0)
BLITER(16, 24, 0)
BLITER(16, 32, 0)
BLITER(32,  8, 0)
BLITER(32, 15, 0)
BLITER(32, 16, 0)
BLITER(32, 24, 0)
BLITER(32, 32, 0)

BLITER(16, 16, 1)
BLITER(16, 24, 1)
BLITER(16, 32, 1)
BLITER(32, 15, 1)
BLITER(32, 16, 1)
BLITER(32, 24, 1)
BLITER(32, 32, 1)

BLITER(16, 16, 2)
BLITER(16, 24, 2)
BLITER(16, 32, 2)
BLITER(32, 15, 2)
BLITER(32, 16, 2)
BLITER(32, 24, 2)
BLITER(32, 32, 2)

#define SET_BLITER(srcbpp, dstbpp, xscale, yscale, scanline, brightness, mmx) \
{ \
    bliter = asmblit_##srcbpp##to##dstbpp##_##xscale##x##yscale##_sl##scanline##_bl##brightness##_mmx##mmx;  \
    DebugMsg(("asmblit_" #srcbpp "to" #dstbpp "_" #xscale "x" #yscale "_sl" #scanline "_bl" #brightness "_mmx" #mmx "\n")); \
}

#ifdef NFILTER
#define SELECT_BLITER(srcbpp, dstbpp, mmx)                   \
{                                                            \
    if (bHDouble)                                            \
    {                                                        \
        if (bVScanLines)                                     \
        {                                                    \
            if (nSLBrightness == 75)                         \
                SET_BLITER(srcbpp, dstbpp, 2, 1, 2, 75, mmx) \
            else if (nSLBrightness == 50)                    \
                SET_BLITER(srcbpp, dstbpp, 2, 1, 2, 50, mmx) \
            else if (nSLBrightness == 25)                    \
                SET_BLITER(srcbpp, dstbpp, 2, 1, 2, 25, mmx) \
            else                                             \
                SET_BLITER(srcbpp, dstbpp, 2, 1, 2,  0, mmx) \
        }                                                    \
        else                                                 \
            SET_BLITER(srcbpp, dstbpp, 2, 1, 0, 0, mmx)      \
    }                                                        \
    else if (bVDouble)                                       \
    {                                                        \
        if (bHScanLines)                                     \
        {                                                    \
            if (nSLBrightness == 75)                         \
                SET_BLITER(srcbpp, dstbpp, 1, 2, 1, 75, mmx) \
            else if (nSLBrightness == 50)                    \
                SET_BLITER(srcbpp, dstbpp, 1, 2, 1, 50, mmx) \
            else if (nSLBrightness == 25)                    \
                SET_BLITER(srcbpp, dstbpp, 1, 2, 1, 25, mmx) \
            else                                             \
                SET_BLITER(srcbpp, dstbpp, 1, 2, 1,  0, mmx) \
        }                                                    \
        else                                                 \
            SET_BLITER(srcbpp, dstbpp, 1, 2, 0, 0, mmx)      \
    }                                                        \
    else if (bHScanLines)                                    \
    {                                                        \
        if (nSLBrightness == 75)                             \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 1, 75, mmx)     \
        else if (nSLBrightness == 50)                        \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 1, 50, mmx)     \
        else if (nSLBrightness == 50)                        \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 1, 25, mmx)     \
        else                                                 \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 1,  0, mmx)     \
    }                                                        \
    else if (bVScanLines)                                    \
    {                                                        \
        if (nSLBrightness == 75)                             \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 2, 75, mmx)     \
        else if (nSLBrightness == 50)                        \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 2, 50, mmx)     \
        else if (nSLBrightness == 50)                        \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 2, 25, mmx)     \
        else                                                 \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 2,  0, mmx)     \
    }                                                        \
    else if (bDouble || bFilter)                             \
    {                                                        \
        SET_BLITER(srcbpp, dstbpp, 2, 2, 0, 0, mmx)          \
    }                                                        \
    else                                                     \
    {                                                        \
        SET_BLITER(srcbpp, dstbpp, 1, 1, 0, 0, mmx)          \
    }                                                        \
}
#else
#define SELECT_BLITER(srcbpp, dstbpp, mmx)                   \
{                                                            \
    if (bHDouble)                                            \
    {                                                        \
        if (bVScanLines)                                     \
        {                                                    \
            if (nSLBrightness == 75)                         \
                SET_BLITER(srcbpp, dstbpp, 2, 1, 2, 75, mmx) \
            else if (nSLBrightness == 50)                    \
                SET_BLITER(srcbpp, dstbpp, 2, 1, 2, 50, mmx) \
            else if (nSLBrightness == 25)                    \
                SET_BLITER(srcbpp, dstbpp, 2, 1, 2, 25, mmx) \
            else                                             \
                SET_BLITER(srcbpp, dstbpp, 2, 1, 2,  0, mmx) \
        }                                                    \
        else                                                 \
            SET_BLITER(srcbpp, dstbpp, 2, 1, 0, 0, mmx)      \
    }                                                        \
    else if (bVDouble)                                       \
    {                                                        \
        if (bHScanLines)                                     \
        {                                                    \
            if (nSLBrightness == 75)                         \
                SET_BLITER(srcbpp, dstbpp, 1, 2, 1, 75, mmx) \
            else if (nSLBrightness == 50)                    \
                SET_BLITER(srcbpp, dstbpp, 1, 2, 1, 50, mmx) \
            else if (nSLBrightness == 25)                    \
                SET_BLITER(srcbpp, dstbpp, 1, 2, 1, 25, mmx) \
            else                                             \
                SET_BLITER(srcbpp, dstbpp, 1, 2, 1,  0, mmx) \
        }                                                    \
        else                                                 \
            SET_BLITER(srcbpp, dstbpp, 1, 2, 0, 0, mmx)      \
    }                                                        \
    else if (bHScanLines)                                    \
    {                                                        \
        if (nSLBrightness == 75)                             \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 1, 75, mmx)     \
        else if (nSLBrightness == 50)                        \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 1, 50, mmx)     \
        else if (nSLBrightness == 50)                        \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 1, 25, mmx)     \
        else                                                 \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 1,  0, mmx)     \
    }                                                        \
    else if (bVScanLines)                                    \
    {                                                        \
        if (nSLBrightness == 75)                             \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 2, 75, mmx)     \
        else if (nSLBrightness == 50)                        \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 2, 50, mmx)     \
        else if (nSLBrightness == 50)                        \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 2, 25, mmx)     \
        else                                                 \
            SET_BLITER(srcbpp, dstbpp, 2, 2, 2,  0, mmx)     \
    }                                                        \
    else if (bDouble)                                        \
    {                                                        \
        SET_BLITER(srcbpp, dstbpp, 2, 2, 0, 0, mmx)          \
    }                                                        \
    else                                                     \
    {                                                        \
        SET_BLITER(srcbpp, dstbpp, 1, 1, 0, 0, mmx)          \
    }                                                        \
}
#endif

#if 0
#define DebugMsg(x)  ErrorMsg x
#else
#define DebugMsg(x)  logerror x
#endif

/****************************************************************************
    Functions
 ***************************************************************************/

bliter_func select_bliter(int nSrcDepth,
                          int nDstDepth,
                          BOOL bDouble,
                          BOOL bBltDouble,
#ifdef NFILTER
                          BOOL bFilter,
#endif
                          BOOL bHDouble,
                          BOOL bVDouble,
                          BOOL bHScanLines,
                          BOOL bVScanLines,
                          int  nSLBrightness,
                          BOOL bDisableMMX,
                          BOOL bDisableMMX2)
{
    bliter_func bliter = NULL;

    switch (nDstDepth)
    {
    case 15: brightmask[0] = brightmask[1] = 0x3def3def; break;
    case 16: brightmask[0] = brightmask[1] = 0x7bef7bef; break;
    case 24: brightmask[0] = brightmask[1] = 0x7f7f7f7f; break;
    case 32: brightmask[0] = brightmask[1] = 0x007f7f7f; break;
    default: brightmask[0] = brightmask[1] = 0x00000000; break;
    }

    if (bDisableMMX2 == FALSE)
    {
        if (nSrcDepth == 15 || nSrcDepth == 16)
        {
            switch (nDstDepth)
            {
            case 15:
            case 16:
                SELECT_BLITER(16, 16, 2)
                break;

            case 24:
                SELECT_BLITER(16, 24, 2)
                break;

            case 32:
                SELECT_BLITER(16, 32, 2)
                break;
            }
        }
        else if (nSrcDepth == 32)
        {
            switch (nDstDepth)
            {
            case 15:
                SELECT_BLITER(32, 15, 2)
                break;

            case 16:
                SELECT_BLITER(32, 16, 2)
                break;

            case 24:
                SELECT_BLITER(32, 24, 2)
                break;

            case 32:
                SELECT_BLITER(32, 32, 2)
                break;
            }
        }
    }

    if (bliter != NULL)
        return bliter;

    if (bDisableMMX == FALSE)
    {
        if (nSrcDepth == 15 || nSrcDepth == 16)
        {
            switch (nDstDepth)
            {
            case 15:
            case 16:
                SELECT_BLITER(16, 16, 1)
                break;

            case 24:
                SELECT_BLITER(16, 24, 1)
                break;

            case 32:
                SELECT_BLITER(16, 32, 1)
                break;
            }
        }
        else if (nSrcDepth == 32)
        {
            switch (nDstDepth)
            {
            case 15:
                SELECT_BLITER(32, 15, 1)
                break;

            case 16:
                SELECT_BLITER(32, 16, 1)
                break;

            case 24:
                SELECT_BLITER(32, 24, 1)
                break;

            case 32:
                SELECT_BLITER(32, 32, 1)
                break;
            }
        }
    }

    if (bliter != NULL)
        return bliter;

    if (nSrcDepth == 15 || nSrcDepth == 16)
    {
        switch (nDstDepth)
        {
        case 15:
        case 16:
            SELECT_BLITER(16, 16, 0)
            break;

        case 24:
            SELECT_BLITER(16, 24, 0)
            break;

        case 32:
            SELECT_BLITER(16, 32, 0)
            break;
        }
    }
    else if (nSrcDepth == 32)
    {
        switch (nDstDepth)
        {
        case 15:
            SELECT_BLITER(32, 15, 0)
            break;

        case 16:
            SELECT_BLITER(32, 16, 0)
            break;

        case 24:
            SELECT_BLITER(32, 24, 0)
            break;

        case 32:
            SELECT_BLITER(32, 32, 0)
            break;
        }
    }

    if (bliter == NULL)
#ifdef JAPANESE
        ErrorMsg("%dbpp→%dbppはサポートしていません", nSrcDepth, nDstDepth);
#else
        ErrorMsg("blit %dbpp to %dbpp:Not supported.", nSrcDepth, nDstDepth);
#endif

    return bliter;
}
