///////////////////////////////////////////////////////////////////////////////
// Copyright (C) Microsoft Corporation, 2000.
//
// refrast.cpp
//
// Direct3D Reference Device - rasterizer miscellaneous
//
///////////////////////////////////////////////////////////////////////////////
#include "pch.cpp"
#pragma hdrstop

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// RDColor                                                                   //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
void
RDColor::ConvertFrom( RDSurfaceFormat Type, const char* pSurfaceBits )
{
    UINT16 u16BITS;
    UINT8 u8BITS;

    switch (Type)
    {
    default:
    case RD_SF_NULL: return;
    case RD_SF_B8G8R8A8: *this = *((UINT32*)pSurfaceBits); break;
    case RD_SF_B8G8R8X8: *this = *((UINT32*)pSurfaceBits); A = 1.F; break;

    case RD_SF_B5G6R5:
        u16BITS = *((UINT16*)pSurfaceBits);
        R = ((u16BITS>>(6+5)) & 0x001F)/31.f;
        G = ((u16BITS>>   5) & 0x003F)/63.f;
        B = ((u16BITS      ) & 0x001F)/31.f;
        A = 1.F;
        break;

    case RD_SF_B5G5R5X1:
        u16BITS = *((UINT16*)pSurfaceBits);
        R = ((u16BITS>>(5+5)) & 0x001F)/31.f;
        G = ((u16BITS>>   5) & 0x001F)/31.f;
        B = ((u16BITS      ) & 0x001F)/31.f;
        A = 1.F;
        break;

    case RD_SF_B5G5R5A1:
        u16BITS = *((UINT16*)pSurfaceBits);
        R = ((u16BITS>>(5+5)) & 0x001F)/31.f;
        G = ((u16BITS>>   5) & 0x001F)/31.f;
        B = ((u16BITS      ) & 0x001F)/31.f;
        A = ( u16BITS & 0x8000 ) ? 1.f : 0.f;
        break;

    case RD_SF_B4G4R4A4:
        u16BITS = *((UINT16*)pSurfaceBits);
        R = ((u16BITS>>  (4+4)) & 0x000F)/15.f;
        G = ((u16BITS>>    (4)) & 0x000F)/15.f;
        B = ((u16BITS         ) & 0x000F)/15.f;
        A = ((u16BITS>>(4+4+4)) & 0x000F)/15.f;
        break;

    case RD_SF_B4G4R4X4:
        u16BITS = *((UINT16*)pSurfaceBits);
        R = ((u16BITS>>(4+4)) & 0x000F)/15.f;
        G = ((u16BITS>>  (4)) & 0x000F)/15.f;
        B = ((u16BITS       ) & 0x000F)/15.f;
        A = 1.f;
        break;

    case RD_SF_B8G8R8:
        R = *((UINT8*)pSurfaceBits+2)/255.f;
        G = *((UINT8*)pSurfaceBits+1)/255.f;
        B = *((UINT8*)pSurfaceBits+0)/255.f;
        A = 1.F;
        break;

    case RD_SF_L8:
        R = G = B = *((UINT8*)pSurfaceBits)/255.f;
        A = 1.F;
        break;

    case RD_SF_L8A8:
        u16BITS = *((UINT16*)pSurfaceBits);
        R = G = B = (UINT8)(0xff & u16BITS)/255.f;
        A = (UINT8)(0xff & (u16BITS >> 8))/255.f;
        break;

    case RD_SF_A8:
        R = G = B = 0.f;
        A = *((UINT8*)pSurfaceBits)/255.f;
        break;

    case RD_SF_B2G3R3:
        u8BITS = *((UINT8*)pSurfaceBits);
        R = ((u8BITS>>(3+2)) & 0x07)/7.f;
        G = ((u8BITS>>   2) & 0x07)/7.f;
        B = ((u8BITS      ) & 0x03)/3.f;
        A = 1.F;
        break;

    case RD_SF_L4A4:
        u16BITS = *((UINT8*)pSurfaceBits);
        R = G = B = (u16BITS & 0x0f)/15.f;
        A =    ((u16BITS>>4) & 0x0f)/15.f;
        break;

    case RD_SF_B2G3R3A8:
        u16BITS = *((UINT16*)pSurfaceBits);
        R = ((u16BITS>>(3+2)) & 0x07)/7.f;
        G = ((u16BITS>>   2) & 0x07)/7.f;
        B = ((u16BITS      ) & 0x03)/3.f;
        A = (UINT8)(0xff & (u16BITS >> 8))/255.f;
        break;

    case RD_SF_U8V8:
        {
            INT8 iDU = *(( INT8*)pSurfaceBits+0);
            INT8 iDV = *(( INT8*)pSurfaceBits+1);
            R = CLAMP_SIGNED8(iDU);     // fDU
            G = CLAMP_SIGNED8(iDV);     // fDV
            B = 1.0F;                   // fL
            A = 1.F;
        }
        break;

    case RD_SF_U16V16:
        {
            INT16 iDU = *(( INT16*)pSurfaceBits+0);
            INT16 iDV = *(( INT16*)pSurfaceBits+1);
            R = CLAMP_SIGNED16(iDU);     // fDU
            G = CLAMP_SIGNED16(iDV);     // fDV
            B = 1.0f;   // 1.0 here is intentional
            A = 1.0f;
        }
        break;

    case RD_SF_U5V5L6:
        {
            UINT16 u16BITS = *((UINT16*)pSurfaceBits);
            INT8 iDU = (INT8)(u16BITS & 0x1f);
            INT8 iDV = (INT8)((u16BITS>>5) & 0x1f);
            UINT8 uL = (UINT8)(u16BITS >> 10);
            R = CLAMP_SIGNED5(iDU);      // fDU
            G = CLAMP_SIGNED5(iDV);      // fDV
            // the unsigned uL is normalized with 2^N - 1, since this is the
            // largest representable value
            B = (FLOAT)uL * (1.0F/63.0F);       // fL
            A = 1.0f;
        }
        break;

    case RD_SF_U8V8L8X8:
        {
            INT8 iDU = *(( INT8*)pSurfaceBits+0);
            INT8 iDV = *(( INT8*)pSurfaceBits+1);
            UINT8 uL  = *((UINT8*)pSurfaceBits+2);
            R = CLAMP_SIGNED8(iDU);     // fDU
            G = CLAMP_SIGNED8(iDV);     // fDV
            // the unsigned uL is normalized with 2^N - 1, since this is the
            // largest representable value
            B = (FLOAT)uL * (1.0F/255.0F);      // fL
            A = 1.0f;
        }
        break;
    case RD_SF_U8V8W8Q8:
        {
            INT8 iDU = *(( INT8*)pSurfaceBits+0);
            INT8 iDV = *(( INT8*)pSurfaceBits+1);
            INT8 iDW = *(( INT8*)pSurfaceBits+2);
            INT8 iDQ = *(( INT8*)pSurfaceBits+3);
            // signed values are normalized with 2^(N-1), since -2^(N-1) can
            // be exactly expressed in N bits
            R = CLAMP_SIGNED8(iDU);     // fDU
            G = CLAMP_SIGNED8(iDV);     // fDV
            B = CLAMP_SIGNED8(iDW);     // fDW
            A = CLAMP_SIGNED8(iDQ);     // fDQ
        }
        break;
    case RD_SF_U10V11W11:
        {
            UINT32 u32BITS = *((UINT32*)pSurfaceBits);
            INT16 iDU = (INT16)((u32BITS>>(0    )) & 0x3FF);
            INT16 iDV = (INT16)((u32BITS>>(10   )) & 0x7FF);
            INT16 iDW = (INT16)((u32BITS>>(10+11)) & 0x7FF);

            // signed values are normalized with 2^(N-1), since -2^(N-1) can
            // be exactly expressed in N bits
            R = CLAMP_SIGNED10(iDU);    // fDU
            G = CLAMP_SIGNED11(iDV);    // fDV
            B = CLAMP_SIGNED11(iDW);    // fDW
            A = 1.0f;
        }
        break;
    case RD_SF_R10G10B10A2:
        {
            UINT32 u32BITS = *((UINT32*)pSurfaceBits);
            R = ((u32BITS>>(0    ))  & 0x3FF)/1023.f;
            G = ((u32BITS>>(10   ))  & 0x3FF)/1023.f;
            B = ((u32BITS>>(10+10))  & 0x3FF)/1023.f;
            A = ((u32BITS>>(10+10+10)) & 0x3)/3.f;
        }
    break;
    case RD_SF_R8G8B8A8:
        {
            R = *(( UINT8*)pSurfaceBits+0)/255.f;
            G = *(( UINT8*)pSurfaceBits+1)/255.f;
            B = *(( UINT8*)pSurfaceBits+2)/255.f;
            A = *(( UINT8*)pSurfaceBits+3)/255.f;
        }
    break;
    case RD_SF_R8G8B8X8:
        {
            R = *(( UINT8*)pSurfaceBits+0)/255.f;
            G = *(( UINT8*)pSurfaceBits+1)/255.f;
            B = *(( UINT8*)pSurfaceBits+2)/255.f;
            A = 1.f;
        }
    break;
    case RD_SF_R16G16:
        {
            R = *(( UINT16*)pSurfaceBits+0)/65535.f;
            G = *(( UINT16*)pSurfaceBits+1)/65535.f;
            B = 1.0f;   // 1.0 here is intentional
            A = 1.0f;
        }
    break;
    case RD_SF_U11V11W10:
        {
            UINT32 u32BITS = *((UINT32*)pSurfaceBits);
            INT16 iDU = (INT16)((u32BITS>>(0    )) & 0x7FF);
            INT16 iDV = (INT16)((u32BITS>>(11   )) & 0x7FF);
            INT16 iDW = (INT16)((u32BITS>>(11+11)) & 0x3FF);

            // signed values are normalized with 2^(N-1), since -2^(N-1) can
            // be exactly expressed in N bits
            R = CLAMP_SIGNED11(iDU);    // fDU
            G = CLAMP_SIGNED11(iDV);    // fDV
            B = CLAMP_SIGNED10(iDW);    // fDW
            A = 1.0f;
        }
    break;
    case RD_SF_U10V10W10A2:
        {
            UINT32 u32BITS = *((UINT32*)pSurfaceBits);
            INT16 iDU = (INT16)((u32BITS>>(0    )) & 0x3FF);
            INT16 iDV = (INT16)((u32BITS>>(10   )) & 0x3FF);
            INT16 iDW = (INT16)((u32BITS>>(10+10)) & 0x3FF);

            // signed values are normalized with 2^(N-1), since -2^(N-1) can
            // be exactly expressed in N bits
            R = CLAMP_SIGNED10(iDU);    // fDU
            G = CLAMP_SIGNED10(iDV);    // fDV
            B = CLAMP_SIGNED10(iDW);    // fDW

            // Note: The A component is treated as an unsigned component
            A = ((u32BITS>>(10+10+10)) & 0x3)/3.f; 
        }
    break;
    case RD_SF_U8V8X8A8:
        {
            INT8 iU = *(( INT8*)pSurfaceBits+0);
            INT8 iV = *(( INT8*)pSurfaceBits+1);
            
            // signed values are normalized with 2^(N-1), since -2^(N-1) can
            // be exactly expressed in N bits
            R = CLAMP_SIGNED8(iU);
            G = CLAMP_SIGNED8(iV);
            B = 1.0f;

            // Note: The A component is treated as unsigned 
            A = *(( INT8*)pSurfaceBits+3)/255.f;
        }
    break;
    case RD_SF_U8V8X8L8:
        {
            INT8 iU = *(( INT8*)pSurfaceBits+0);
            INT8 iV = *(( INT8*)pSurfaceBits+1);
            INT8 iL = *(( INT8*)pSurfaceBits+3);
            
            // signed values are normalized with 2^(N-1), since -2^(N-1) can
            // be exactly expressed in N bits
            R = CLAMP_SIGNED8(iU);
            G = CLAMP_SIGNED8(iV);
            B = CLAMP_SIGNED8(iL);
            A = 1.0f;
        }
    break;
    // shadow map texture formats (read only, not needed for ConvertTo)
    case RD_SF_Z16S0:
        {
            UINT16 u16BITS = *((UINT16*)pSurfaceBits);
            R = 0.0F;
            G = (FLOAT)u16BITS * (1.0F/(FLOAT)0xffff);
            B = 0.0F;
            A = 1.0f;
        }
        break;

    case RD_SF_Z24S8:
    case RD_SF_Z24X8:
    case RD_SF_Z24X4S4:
        {
            UINT32 u32BITS = *((UINT32*)pSurfaceBits);
            R = 0.0F;
            G = (FLOAT)(u32BITS>>8) * (1.0F/(FLOAT)0xffffff);
            B = 0.0F;
            A = 1.0f;
        }
        break;

    case RD_SF_S8Z24:
    case RD_SF_X8Z24:
    case RD_SF_X4S4Z24:
        {
            UINT32 u32BITS = *((UINT32*)pSurfaceBits);
            R = 0.0F;
            G = (FLOAT)(u32BITS&0x00ffffff) * (1.0F/(FLOAT)0xffffff);
            B = 0.0F;
            A = 1.0f;
        }
        break;

    case RD_SF_Z15S1:
        {
            UINT16 u16BITS = *((UINT16*)pSurfaceBits);
            R = 0.0F;
            G = (FLOAT)(u16BITS>>1) * (1.0F/(FLOAT)0x7fff);
            B = 0.0F;
            A = 1.0f;
        }
        break;

    case RD_SF_S1Z15:
        {
            UINT16 u16BITS = *((UINT16*)pSurfaceBits);
            R = 0.0F;
            G = (FLOAT)(u16BITS&0x7fff) * (1.0F/(FLOAT)0x7fff);
            B = 0.0F;
            A = 1.0f;
        }
        break;

    case RD_SF_Z32S0:
        {
            UINT32 u32BITS = *((UINT32*)pSurfaceBits);
            R = 0.0F;
            G = (FLOAT)u32BITS * (1.0F/(FLOAT)0xffffffff);
            B = 0.0F;
            A = 1.0f;
        }
        break;
    }
}

// Convert surface type format to RDColor
void
RDColor::ConvertTo( RDSurfaceFormat Type, float fRoundOffset, char* pSurfaceBits ) const
{
    int iR, iG, iB, iA;

    switch (Type)
    {
    case RD_SF_B8G8R8A8:
        *((UINT8*)pSurfaceBits+0) = (UINT8)((FLOAT)B * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+1) = (UINT8)((FLOAT)G * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+2) = (UINT8)((FLOAT)R * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+3) = (UINT8)((FLOAT)A * 255. + fRoundOffset);
        break;

    case RD_SF_B8G8R8X8:
        *((UINT8*)pSurfaceBits+0) = (UINT8)((FLOAT)B * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+1) = (UINT8)((FLOAT)G * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+2) = (UINT8)((FLOAT)R * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+3) = 0x00;
        break;

    case RD_SF_B8G8R8:
        *((UINT8*)pSurfaceBits+0) = (UINT8)((FLOAT)B * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+1) = (UINT8)((FLOAT)G * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+2) = (UINT8)((FLOAT)R * 255. + fRoundOffset);
        break;

    case RD_SF_B4G4R4A4:
        iA = (FLOAT)A * 15. + fRoundOffset;
        iR = (FLOAT)R * 15. + fRoundOffset;
        iG = (FLOAT)G * 15. + fRoundOffset;
        iB = (FLOAT)B * 15. + fRoundOffset;
        *((UINT16*)pSurfaceBits) = (iA<<12) | (iR<<8) | (iG<<4) | iB;
        break;

    case RD_SF_B4G4R4X4:
        iR = (FLOAT)R * 15. + fRoundOffset;
        iG = (FLOAT)G * 15. + fRoundOffset;
        iB = (FLOAT)B * 15. + fRoundOffset;
        *((UINT16*)pSurfaceBits) = (0x00<<12) | (iR<<8) | (iG<<4) | iB;
        break;

    case RD_SF_B5G6R5:
        iR = (FLOAT)R * 31. + fRoundOffset; // apply rounding bias then truncate
        iG = (FLOAT)G * 63. + fRoundOffset;
        iB = (FLOAT)B * 31. + fRoundOffset;
        *((UINT16*)pSurfaceBits) =            (iR<<11) | (iG<<5) | iB;
        break;

    case RD_SF_B5G5R5A1:
        iA = (FLOAT)A *  1. + fRoundOffset;
        iR = (FLOAT)R * 31. + fRoundOffset;
        iG = (FLOAT)G * 31. + fRoundOffset;
        iB = (FLOAT)B * 31. + fRoundOffset;
        *((UINT16*)pSurfaceBits) = (iA<<15) | (iR<<10) | (iG<<5) | iB;
        break;

    case RD_SF_B5G5R5X1:
        iR = (FLOAT)R * 31. + fRoundOffset;
        iG = (FLOAT)G * 31. + fRoundOffset;
        iB = (FLOAT)B * 31. + fRoundOffset;
        *((UINT16*)pSurfaceBits) = (iR<<10) | (iG<<5) | iB;
        break;

    case RD_SF_B2G3R3:
        iR = (FLOAT)R * 7. + fRoundOffset;
        iG = (FLOAT)G * 7. + fRoundOffset;
        iB = (FLOAT)B * 3. + fRoundOffset;
        *((UINT8*)pSurfaceBits) = (iR<<5) | (iG<<2) | iB;
        break;

    case RD_SF_B2G3R3A8:
        iA = (FLOAT)A * 255. + fRoundOffset;
        iR = (FLOAT)R * 7. + fRoundOffset;
        iG = (FLOAT)G * 7. + fRoundOffset;
        iB = (FLOAT)B * 3. + fRoundOffset;
        *((UINT16*)pSurfaceBits) = (iA<<8) | (iR<<5) | (iG<<2) | iB;
        break;

    case RD_SF_R10G10B10A2:
        iR = (FLOAT)R * 1023.f + fRoundOffset;
        iG = (FLOAT)G * 1023.f + fRoundOffset;
        iB = (FLOAT)B * 1023.f + fRoundOffset;
        iA = (FLOAT)A * 3.f + fRoundOffset;
        *((UINT32*)pSurfaceBits) = (iA<<(10+10+10)) | (iB<<(10+10)) | (iG<<10) | iR;
        break;

    case RD_SF_R8G8B8A8:
        *((UINT8*)pSurfaceBits+0) = (UINT8)((FLOAT)R * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+1) = (UINT8)((FLOAT)G * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+2) = (UINT8)((FLOAT)B * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+3) = (UINT8)((FLOAT)A * 255. + fRoundOffset);
        break;

    case RD_SF_R8G8B8X8:
        *((UINT8*)pSurfaceBits+0) = (UINT8)((FLOAT)R * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+1) = (UINT8)((FLOAT)G * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+2) = (UINT8)((FLOAT)B * 255. + fRoundOffset);
        *((UINT8*)pSurfaceBits+3) = 0x00;
        break;

    }
}

///////////////////////////////////////////////////////////////////////////////
// end