/////////////////////////////////////////////////////////////////////////////// // Copyright (C) Microsoft Corporation, 1998. // // texmap.cpp // // Direct3D Reference Rasterizer - Texture Map Access Methods // /////////////////////////////////////////////////////////////////////////////// #include "pch.cpp" #pragma hdrstop inline UINT8 CLAMP_BYTE(double f) { if (f > 255.0) return 255; if (f < 0.0) return 0; return (BYTE) f; } //----------------------------------------------------------------------------- // TexelFromBlock - decompress a color block and obtain texel color //----------------------------------------------------------------------------- UINT32 TexelFromBlock(RRSurfaceType surfType, char *pblockSrc, int x, int y) { UINT32 index = ((y & 0x3)<<2) + (x & 0x3); DDRGBA colorDst[DXT_BLOCK_PIXELS]; switch(surfType) { case RR_STYPE_DXT1: DecodeBlockRGB((DXTBlockRGB *)pblockSrc, (DXT_COLOR *)colorDst); break; case RR_STYPE_DXT2: case RR_STYPE_DXT3: DecodeBlockAlpha4((DXTBlockAlpha4 *)pblockSrc, (DXT_COLOR *)colorDst); break; case RR_STYPE_DXT4: case RR_STYPE_DXT5: DecodeBlockAlpha3((DXTBlockAlpha3 *)pblockSrc, (DXT_COLOR *)colorDst); break; } return RGBA_MAKE(colorDst[index].red, colorDst[index].green, colorDst[index].blue, colorDst[index].alpha); } //----------------------------------------------------------------------------- // // ReadTexelColor - Reads texel from texture map at given LOD; converts to // RRColor format, applying palette if necessary; also performs colorkey by // zero-ing out alpha // //----------------------------------------------------------------------------- void RRTexture::ReadColor( INT32 iX, INT32 iY, INT32 iLOD, RRColor& Texel, BOOL &bColorKeyMatched ) { if ( (iLOD > m_cLOD) && !(m_uFlags & RR_TEXTURE_ENVMAP) ) { return; } if ( NULL == m_pTextureBits[iLOD] ) { return; } char* pSurfaceBits = PixelAddress( iX, iY, m_pTextureBits[iLOD], m_iPitch[iLOD], m_SurfType ); switch ( m_SurfType ) { default: Texel.ConvertFrom( m_SurfType, pSurfaceBits ); break; case RR_STYPE_PALETTE8: { UINT8 uIndex = *((UINT8*)pSurfaceBits); UINT32 uTexel = *( (UINT32*)(m_pPalette) + uIndex ); Texel = RGBA_MAKE( (uTexel>> 0) & 0xff, (uTexel>> 8) & 0xff, (uTexel>>16) & 0xff, (uTexel>>24) & 0xff); if ( !( m_uFlags & RR_TEXTURE_ALPHAINPALETTE ) ) Texel.A = 1.f; } break; case RR_STYPE_PALETTE4: { UINT8 uIndex = *((INT8*)pSurfaceBits); if ((iX & 1) == 0) { uIndex &= 0xf; } else { uIndex >>= 4; } UINT32 uTexel = *( (UINT32*)(m_pPalette) + uIndex ); Texel = RGBA_MAKE( (uTexel>> 0) & 0xff, (uTexel>> 8) & 0xff, (uTexel>>16) & 0xff, (uTexel>>24) & 0xff); if ( !( m_uFlags & RR_TEXTURE_ALPHAINPALETTE ) ) Texel.A = 1.f; } break; case RR_STYPE_UYVY: case RR_STYPE_YUY2: // Converts a given YUV (8bits each) to RGB scaled between 0 and 255 // These are using the YCrCb to RGB algorithms given on page 30 // in "VIDEO DEMYSTIFIED" by Keith Jack // ISBN#: 1-878707-09-4 // IN PC graphics, even though they call it YUV, it is really YCrCb // formats that are used by most framegrabbers etc. Hence the pixel // data we will obtain in these YUV surfaces will most likely be this // and not the original YUV which is actually used in PAL broadcast // only (NTSC uses YIQ). So really, U should be called Cb (Blue color // difference) and V should be called Cr (Red color difference) // // These equations are meant to handle the following ranges // (from the same book): // Y (16 to 235), U and V (16 to 240, 128 = zero) // ----------- // Y U V // ----------- // White : 180 128 128 // Black : 16 128 128 // Red : 65 100 212 // Green : 112 72 58 // Blue : 35 212 114 // Yellow : 162 44 142 // Cyan : 131 156 44 // Magenta: 84 184 198 // ----------- // It is assumed that the gamma corrected RGB range is (0 - 255) // // UYVY: U0Y0 V0Y1 U2Y2 V2Y3 (low byte always has current Y) // If iX is even, hight-byte has current U (Cb) // If iX is odd, hight-byte has previous V (Cr) // // YUY2: Y0U0 Y1V0 Y2U2 Y3V2 (high byte always has current Y) // (UYVY bytes flipped) // // In this algorithm, we use U and V values from two neighboring // pixels { UINT8 Y, U, V; UINT16 u16Curr = *((UINT16*)pSurfaceBits); UINT16 u16ForU = 0; // Extract U from this UINT16 u16ForV = 0; // Extract V from this // By default we assume YUY2. Change it later if it is UYVY int uvShift = 8; int yShift = 0; if (m_SurfType == RR_STYPE_UYVY) { uvShift = 0; yShift = 8; } if ((iX & 1) == 0) { // Current U available u16ForU = u16Curr; // Obtain V from the next pixel if ( (iX < (m_iWidth >> iLOD)) || (m_uFlags & RR_TEXTURE_ENVMAP) ) { u16ForV = *((UINT16*)PixelAddress( iX+1, iY, m_pTextureBits[iLOD], m_iPitch[iLOD], m_SurfType )); } else { // This case should not be hit because the texture // width is even (actually, a power of two) _ASSERTa(0, "iX exceeds width", u16ForV = u16Curr;) } } else { // Current V available u16ForV = u16Curr; // Obtain U from the previous pixel if (iX > 0) { u16ForU = *((UINT16*)PixelAddress( iX-1, iY, m_pTextureBits[iLOD], m_iPitch[iLOD], m_SurfType )); } else { // This case should not be hit because the texture // width is even (actually, a power of two) _ASSERTa(0, "iX is negative", u16ForU = u16Curr;) } } Y = (u16Curr >> yShift) & 0xff; U = (u16ForU >> uvShift) & 0xff; V = (u16ForV >> uvShift) & 0xff; Texel = RGB_MAKE( CLAMP_BYTE(1.164*(Y-16) + 1.596*(V-128)), CLAMP_BYTE(1.164*(Y-16) - 0.813*(V-128) - 0.391*(U-128)), CLAMP_BYTE(1.164*(Y-16) + 2.018*(U-128)) ); Texel.A = 1.f; } break; // S3 compressed formats: // We have the address to the block, now extract the actual color case RR_STYPE_DXT1: case RR_STYPE_DXT2: case RR_STYPE_DXT3: case RR_STYPE_DXT4: case RR_STYPE_DXT5: Texel = TexelFromBlock(m_SurfType, pSurfaceBits, iX, iY); break; } // colorkey (only supported for legacy behavior) if ( m_bDoColorKeyKill || m_bDoColorKeyZero ) { DWORD dwBits; switch ( m_SurfType ) { default: case RR_STYPE_NULL: return; // don't colorkey unknown or null surfaces case RR_STYPE_PALETTE4: { UINT8 uIndex = *((INT8*)pSurfaceBits); if ((iX & 1) == 0) { uIndex &= 0xf; } else { uIndex >>= 4; } dwBits = (DWORD)uIndex; } break; case RR_STYPE_L8: case RR_STYPE_PALETTE8: case RR_STYPE_B2G3R3: case RR_STYPE_L4A4: { UINT8 uBits = *((UINT8*)pSurfaceBits); dwBits = (DWORD)uBits; } break; case RR_STYPE_B5G6R5: case RR_STYPE_B5G5R5: case RR_STYPE_B5G5R5A1: case RR_STYPE_B4G4R4A4: case RR_STYPE_L8A8: case RR_STYPE_B2G3R3A8: { UINT16 uBits = *((UINT16*)pSurfaceBits); dwBits = (DWORD)uBits; } break; case RR_STYPE_B8G8R8: { UINT32 uBits = 0; uBits |= ( *((UINT8*)pSurfaceBits+0) ) << 0; uBits |= ( *((UINT8*)pSurfaceBits+1) ) << 8; uBits |= ( *((UINT8*)pSurfaceBits+2) ) << 16; dwBits = (DWORD)uBits; } break; case RR_STYPE_B8G8R8A8: case RR_STYPE_B8G8R8X8: { UINT32 uBits = *((UINT32*)pSurfaceBits); dwBits = (DWORD)uBits; } break; } if ( dwBits == m_dwColorKey ) { bColorKeyMatched = TRUE; if (m_bDoColorKeyZero) { Texel.A = 0.F; Texel.R = 0.F; Texel.G = 0.F; Texel.B = 0.F; } } } } /////////////////////////////////////////////////////////////////////////////// // end