//=================================================================
//
// Copyright (c) Microsoft Corporation 1999 - All Rights Reserved.
//
//=================================================================

#ifndef _PIXCONV_
#define _PIXCONV_

#define MUNGED3_SATURATION_MASK_BLUE    (0x1F << 5)
#define MUNGED3_SATURATION_MASK_GREEN   (0x1F << 15)
#define MUNGED3_SATURATION_MASK_RED     (0x1F << 25)
#define MUNGED3_SATURATION_MASK         (MUNGED3_SATURATION_MASK_BLUE | \
                                         MUNGED3_SATURATION_MASK_GREEN | \
                                         MUNGED3_SATURATION_MASK_RED)
#define MUNGED3_SATURATED_BLUE          (0x1F)
#define MUNGED3_SATURATED_GREEN         (0x1F << 10)
#define MUNGED3_SATURATED_RED           (0x1F << 20)

// converts an 888 color to MUNGED3 (stripping alpha)
inline MUNGED3 FROM_888_TO_MUNGED3(DWORD dwColor)
{
    return ((dwColor & 0x000000F8) >> 3) |
         ((dwColor & 0x0000F800) >> 1) |
         ((dwColor & 0x00F80000) << 1);
}

// converts a MUNGED3 color an 888
inline MUNGED3 FROM_MUNGED3_TO_888(DWORD dwColor)
{
    return ((dwColor & 0x0000001F) << 3) |
         ((dwColor & 0x00007C00) << 1) |
         ((dwColor & 0x01F00000) >> 1);
}

// converts an 8888 color to the alpha component (stripping RGB)
inline MUNGED1 FROM_8888_TO_ALPHA(DWORD dwColor)
{
    return dwColor >> 27;
}

// converts an 888 color to GB (stripping alpha and red)
inline MUNGED2X FROM_888_TO_GBX(DWORD dwColor)
{
    return ((dwColor & 0x000000F8) >> 3) |
           ((dwColor & 0x0000F800) >> 0);
}

// converts an 888 color to B (stripping alpha, red, and green)
inline MUNGED1 FROM_888_TO_B(DWORD dwColor)
{
    return (dwColor & 0x000000F8) >> 3;
}

// converts an 8888 color to AR (stripping GB)
inline MUNGED2X FROM_8888_TO_ARX(DWORD dwColor)
{
    return ((dwColor & 0xF8000000) >> 16) |
           ((dwColor & 0x00F80000) >> 19);
}

// converts a 565 color to MUNGED3
inline MUNGED3 FROM_565_TO_MUNGED3(DWORD dwColor)
{
    return (dwColor & 0x0000001F) |
          ((dwColor & 0x000007C0) << 4) |
          ((dwColor & 0x0000F800) << 9);
}

// converts a 555 color to MUNGED3 (stripping alpha)
inline MUNGED3 FROM_555_TO_MUNGED3(DWORD dwColor)
{
    return (dwColor & 0x0000001F) |
          ((dwColor & 0x000003E0) << 5) |
          ((dwColor & 0x00007C00) << 10);
}

// converts a 444 color to MUNGED3 (stripping alpha)
inline MUNGED3 FROM_444_TO_MUNGED3(DWORD dwColor)
{
    return ((dwColor & 0x0000000F) << 1) |
           ((dwColor & 0x000000F0) << 7) |
           ((dwColor & 0x00000F00) << 13);
}

// converts a 1555 color to the alpha component (stripping RGB)
inline MUNGED1 FROM_1555_TO_ALPHA(DWORD dwColor)
{
    if (dwColor & 0x00008000)
        return MAX_ALPHA;
    else
        return 0;
}

// converts a 4444 color to the alpha component (stripping RGB)
inline MUNGED1 FROM_4444_TO_ALPHA(DWORD dwColor)
{
    int dwT = dwColor & 0x0000F000;

    // we want to make sure an alpha of 0 is completely transparent,
    // but also want an alpha of 0x0F to be completely opaque, so
    // we choose to bump up all non-zero alphas, so alpha will be
    // biased a little high
    if (dwT == 0)
        return 0;
    else
        return (dwT >> 11) + 1;
}

// converts a 1555 color to MUNGED2 GB (stripping AR)
inline MUNGED2 FROM_1555_TO_MUNGED2GB(DWORD dwColor)
{
    return (dwColor & 0x0000001F) |
          ((dwColor & 0x000003E0) << 5);
}

// converts a 1555 color to MUNGED2 AR (stripping GB)
inline MUNGED3 FROM_1555_TO_MUNGED2AR(DWORD dwColor)
{
    DWORD   t;

    if (dwColor & 0x00008000)
        t = MAX_ALPHA << 10;
    else
        t = 0;

    return dwColor |
          ((dwColor & 0x00007C00) >> 10);
}

// converts a MUNGED3 to a GB MUNGED2.
inline MUNGED2 MUNGED3_TO_MUNGED2_GB(MUNGED3 m3)
{
    return m3 & 0x7C1F;
}

// converts a MUNGED3 and an alpha to an AR MUNGED2.
inline MUNGED2 MUNGED3_AND_ALPHA_TO_MUNGED2_AR(MUNGED3 m3, DWORD dwAlpha)
{
    return (m3 >> 20) | (dwAlpha << 10);
}

// converts a MUNGED3 to an R MUNGED2.
inline MUNGED2 MUNGED3_TO_MUNGED2_R(MUNGED3 m3)
{
    return m3 >> 20;
}

// converts a MUNGED2X AR to a MUNGED1.
inline MUNGED1 MUNGED2X_AR_TO_MUNGED1(MUNGED2X m2xAR)
{
    return m2xAR >> 11;
}

// converts a MUNGED2 AR to alpha.
inline MUNGED1 MUNGED2_AR_TO_ALPHA(MUNGED2 m2)
{
    return m2 >> 10;
}

// converts the R of one MUNGED3 and the B of a second MUNGED3 to a BR MUNGED2.
inline MUNGED3_PAIR_TO_MUNGED2_BR(MUNGED3 m31, MUNGED3 m32)
{
    return (m31 >> 20) | ((m32 & 0x1F) << 10);
}

// converts a MUNGED3 to a RG MUNGED2.
inline MUNGED2 MUNGED3_TO_MUNGED2_RG(MUNGED3 m3)
{
    return (m3 & 0x01F07C00) >> 10;
}

// builds a GOURAUD_RB (red/blue) value out of 5.5 red and blue values.
inline GOURAUD_RB BUILD_GRB(FIX5_5 fix5Red, FIX5_5 fix5Blue)
{
    return ((fix5Red & 0x3FF) << 20) | (fix5Blue & 0x3FF);
}

// builds a GOURAUD_G (green) value out of a 5.5 green value
// (alpha is implicitly 0).
inline GOURAUD_AG BUILD_GG(FIX5_5 fix5Green)
{
    return (fix5Green & 0x3FF) << 10;
}

// builds a GOURAUD_AG (alpha/green) value out of 5.5 alpha a green values.
inline GOURAUD_AG BUILD_GAG(FIX5_5 fix5Alpha, FIX5_5 fix5Green)
{
    return ((fix5Alpha & 0x3FF) << 21) | ((fix5Green & 0x3FF) << 10);
}

// builds a GOURAUD_I (intensity) value out of a 5.5 intensity value.
inline GOURAUD_I BUILD_GI(DWORD dwIntensity)
{
    return dwIntensity;
}

// builds a GOURAUD_A (alpha) value out of a 16.16 alpha value.
inline GOURAUD_A BUILD_GA(FIX16_16 fix16Alpha)
{
    return fix16Alpha;
}

// builds a GOURAUD_GB (green/blue) value out of 5.5 green and blue values.
inline GOURAUD_GB BUILD_GGB(FIX5_5 fix5Green, FIX5_5 fix5Blue)
{
    return ((fix5Green & 0x3FF) << 11) | (fix5Blue & 0x3FF);
}

// builds a GOURAUD_AR (alpha/red) value out of 5.5 alpha and red values.
inline GOURAUD_AR BUILD_GAR(FIX5_5 fix5Alpha, FIX5_5 fix5Red)
{
    return ((fix5Alpha & 0x3FF) << 11) | (fix5Red & 0x3FF);
}

// builds a GOURAUD_AR (alpha/red) value out of a 5.5 red value.
inline GOURAUD_AR BUILD_GR(FIX5_5 fix5Red)
{
    return fix5Red & 0x3FF;
}

// builds a GOURAUD_RGB (red/green/blue) value out of 5.5 red, green, and blue values.
inline GOURAUD_RGB BUILD_GRGB(FIX5_5 fix5Red, FIX5_5 fix5Green, FIX5_5 fix5Blue)
{
    return ((fix5Red & 0x3FF) << 22) | ((fix5Green & 0x3FF) << 11) | (fix5Blue & 0x3FF);
}

// turns a GOURAUD_GB into a MUNGED2X.
inline MUNGED2 GOURAUD_GB_TO_MUNGED2X(GOURAUD_GB ggb)
{
    return (ggb >> 5) & 0x0000F81F;
}

// turns a GOURAUD_AR into a MUNGED2X.
inline MUNGED2 GOURAUD_AR_TO_MUNGED2X(GOURAUD_AR gar)
{
    return (gar >> 5) & 0x0000F81F;
}

// turns a GOURAUD_RGB into a MUNGED2X GB.
inline MUNGED2 GOURAUD_RGB_TO_MUNGED2X_GB(GOURAUD_RGB grgb)
{
    return (grgb >> 5) & 0x0000F81F;
}

// turns the R of one GOURAUD_RGB and the B of another GOURAUD_RGB into a MUNGED2X BR.
inline MUNGED2 GOURAUD_RGB_TO_MUNGED2X_BR(GOURAUD_RGB grgb1, GOURAUD_RGB grgb2)
{
    return (grgb1 >> 27) | ((grgb2 & 0x3E0) << 6);
}

// turns a GOURAUD_RGB into a MUNGED2X RG.
inline MUNGED2 GOURAUD_RGB_TO_MUNGED2X_RG(GOURAUD_RGB grgb)
{
    return (grgb >> 16) & 0x0000F81F;
}

// turns a GOURAUD_RGB into a MUNGED2X R.
inline MUNGED2 GOURAUD_RGB_TO_MUNGED2X_R(GOURAUD_RGB grgb)
{
    return (grgb >> 27) & 0x0000001F;
}

// combines and converts a GOURAUD_RB and a GOURAUD_AG to MUNGED3.
inline MUNGED3 GOURAUD_RB_AG_TO_MUNGED3(GOURAUD_RB grb, GOURAUD_AG gag)
{
    DWORD   t;

    t = grb | gag;
    t >>= 5;
    t &= 0x1F07C1F;
    return t;
}

// combines and converts a GOURAUD_RB and a GOURAUD_AG to MUNGED3 and a MUNGED1.
inline void GOURAUD_RB_AG_TO_MUNGED3_AND_MUNGED1(GOURAUD_RB grb, GOURAUD_AG gag,
                                                 MUNGED3 *pm3, MUNGED1 *pm1)
{
    DWORD   t;

    t = grb | (gag & 0x000FFC00);
    t >>= 5;
    t &= 0x1F07C1F;
    *pm3 = t;
    *pm1 = gag >> 26;
}


// converts a GOURAUD_I to a 5-bit intensity value.
inline MUNGED1 GOURAUD_I_TO_MUNGED1(GOURAUD_I gi)
{
    return (gi >> 5) & 0x1F;
}

// converts a GOURAUD_A to a 5-bit intensity value.
inline MUNGED1 GOURAUD_A_TO_MUNGED1(GOURAUD_A ga)
{
    return (ga >> 19) & 0x1F;
}

//----------------------------------------------------------------------
// All these multiply routines adds 1F (1-epsilon) after doing the
// multiplication, so the highest possible resulting value is
// 1F (1.0) and the lowest is 0 (0.0). However, the range is still only
// 00.1F to 1F.00; 1F and 0 are barely touched, so the values are too
// compressed.
//----------------------------------------------------------------------

// multiplies two MUNGED2X values comprising an RGBA value times two
// MUNGED2 values and stores the RGB and alpha results 
inline void MUL_MUNGED2X_TIMES_MUNGED2_RGBA_WITH_FIXUP(MUNGED2X m2xGB, MUNGED2X m2xAR,
                                                       MUNGED2 m2GB, MUNGED2 m2AR,
                                                       MUNGED3 *pm3, MUNGED1 *pm1)
{
    DWORD t, t2;

    t = (m2xGB * m2GB) + 0x03E0001F;
    t &= 0x7C0003E0;
    t = (t >> 16) | ((t >> 5) & 0x1F);
    t2 = (m2xAR * m2AR) + 0x03E0001F;
    t |= (t2 & 0x3E0) << 15;
    *pm3 = t;
    *pm1 = t2 >> 26;
}

// multiplies two MUNGED2X values comprising an RGB value times two
// MUNGED2 values (doesn't really matter which is which) and stores
// the RGB result
inline MUNGED3 MUL_MUNGED2X_TIMES_MUNGED2_RGB_WITH_FIXUP(MUNGED2X m2xGB, MUNGED2X m2xR,
                                                         MUNGED2 m2GB, MUNGED2 m2R)
{
    DWORD t, t2;

    t = (m2xGB * m2GB) + 0x03E0001F;
    t &= 0x7C0003E0;
    t = (t >> 16) | ((t >> 5) & 0x1F);
    t2 = (m2xR * m2R) + 0x0000001F;
    t |= (t2 & 0x3E0) << 15;
    return t;
}


// multiplies three MUNGED2X values comprising two RGB values times three
// MUNGED2 values and stores both RGB results 
inline void MUL_MUNGED2X_TRIO_TIMES_MUNGED2_TRIO_RGB_WITH_FIXUP(MUNGED2X m2xGB, MUNGED2X m2xBR, MUNGED2X m2xRG,
                                                                MUNGED2 m2GB, MUNGED2 m2BR, MUNGED2 m2RG,
                                                                MUNGED3 *pm31, MUNGED3 *pm32)
{
    DWORD t, t2, t3;

    t = (m2xGB * m2GB) + 0x03E0001F;
    t &= 0x7C0003E0;
    t = (t >> 16) | ((t >> 5) & 0x1F);
    t2 = (m2xBR * m2BR) + 0x03E0001F;
    t |= (t2 & 0x3E0) << 15;
    *pm31 = t;
    t2 &= 0x7C000000;
    t2 >>= 26;
    t3 = (m2xRG * m2RG) + 0x03E0001F;
    t2 |= (t3 & 0x7C000000) >> 6;
    t2 |= (t3 & 0x000003E0) << 5;
    *pm32 = t2;
}


// multiplies a 5-bit value by a 5-bit value and returns a 5-bit value
inline MUNGED1 MUL_MUNGED1_TIMES_MUNGED1_WITH_FIXUP(MUNGED1 m1, MUNGED1 m2)
{
    return ((m1 * m2) + 0x1F) >> 5;
}


// multiplies an 8-bit value by an 8-bit value and returns an 8-bit value
inline MUL_INT8_TIMES_INT8_WITH_FIXUP(DWORD m1, DWORD m2)
{
    return ((m1 * m2) + 0xFF) >> 8;
}


// Multiplies a 5-bit value times a MUNGED3 value and returns the result.
inline MUNGED3 MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(MUNGED3 m3, MUNGED1 m1)
{
    DWORD   t;

    t = (m1 * m3) + 0x1F07C1F;
    t = (t & 0x3E0F83E0) >> 5;
    return t;
}


// converts 4-byte munged format to the target format (555 or 565)
inline unsigned short FROM_MUNGED3_TO_TARGET(MUNGED3 m3)
{
    return (unsigned short)
           ((m3 & 0x0000001F) |
           ((m3 & 0x00007C00) >> g_grdChunkData.cMunged3ToTargetShift0) |
           ((m3 & 0x01F00000) >> g_grdChunkData.cMunged3ToTargetShift1));
}


#define SIZE_RGPSPANFNTRIVIALZANDBACKEND    118
extern "C" PSPANFN rgpspanfnTrivialZAndBackend[SIZE_RGPSPANFNTRIVIALZANDBACKEND];

extern "C" void SpanTexture_Wrap(void);
extern "C" void SpanTrivialZ_W(void);
extern "C" void SpanTrivialZ_W_Native(void);
extern "C" void SpanMunge_565(void);
extern "C" void SpanMunge_555(void);
extern "C" void SpanTextureBackend_Wrap_Native_NoZ_10_NoAlphaTest(void);
extern "C" void SpanTextureBackend2X_Wrap_Native_NoZ_10_NoAlphaTest(void);
extern "C" void SpanShade_GouraudRGB(void);

void SpanTextureBackend_Wrap_Native_NoZ_10_NoAlphaTest(void);
void SpanShadeBackend_Native_Flat_NoZ_10_NoAlphaTest(void);
void SpanShadeBackend2X_Native_Flat_NoZ_10_NoAlphaTest(void);
void SpanShadeBackend_Native_Gouraud_NoZ_10_NoAlphaTest(void);
void SpanShadeBackend2X_Native_Gouraud_NoZ_10_NoAlphaTest(void);
void SpanFog_FlatIMul(void);
void SpanFog_GouraudIMul(void);
void SpanFog_MonoGouraudIMul(void);
void SpanTexture_Clamp(void);
void SpanTexture_ClampUWrapV(void);
void SpanTexture_WrapUClampV(void);

// texturing routines need to be externally available to be patched into
// rgpspanfn
void SpanMunge_1555(void);
void SpanMunge_555(void);
void SpanMunge_565(void);
void SpanMunge_4444(void);

#endif // _PIXCONV_

