/////////////////////////////////////////////////////////////////////////////// // Copyright (C) Microsoft Corporation, 1998. // // dxtn.cpp // // Direct3D Reference Rasterizer - DXTn texture compression functions // /////////////////////////////////////////////////////////////////////////////// #include "pch.cpp" // Primary color components (use DirextX byte ordering) #undef RED #define RED 0 #undef GRN #define GRN 1 #undef BLU #define BLU 2 #undef ALFA #define ALFA 3 typedef struct { float rgba[4]; } FCOLOR; // internal color format // // Processing all primaries is such a common idiom // that we define a macro for this action. // Any self-respecting C compiler should easily optimize // this by unrolling the loop! // #define ForAllPrimaries for( primary = 0; primary < NUM_PRIMARIES; ++primary) // Similarly, processing all pixels in a block is a common idiom. #define ForAllPixels for(pixel=0; pixel < DXT_BLOCK_PIXELS; ++pixel) #define NUM_PRIMARIES 3 #define NUM_COMPONENTS 4 // // Quantization constants for RGB565 // #define PRIMARY_BITS 8 #define RED_BITS 5 #define GRN_BITS 6 #define BLU_BITS 5 #define RED_SHIFT (PRIMARY_BITS-RED_BITS) #define GRN_SHIFT (PRIMARY_BITS-GRN_BITS) #define BLU_SHIFT (PRIMARY_BITS-BLU_BITS) #if 0 #define RED_MASK 0xf8 #define GRN_MASK 0xfc #define BLU_MASK 0xf8 #endif // Weighting for each primary based on NTSC luminance static float wtPrimary[NUM_PRIMARIES] = { 0.0820f, // blue 0.6094f, // green 0.3086f // red }; //----------------------------------------------------------------------------- // // unpack a fixed point color // //----------------------------------------------------------------------------- static void RGBToColor (RGB565 *prgb, DXT_COLOR *pcolor) { WORD rgb; DXT_COLOR color; rgb = *((WORD *)prgb); // pick off bits in groups of 5, 6, and 5 color.rgba[BLU] = (unsigned char) rgb; rgb >>= BLU_BITS; color.rgba[GRN] = (unsigned char) rgb; rgb >>= GRN_BITS; color.rgba[RED] = (unsigned char) rgb; // shift primaries into the appropriate LSBs color.rgba[BLU] <<= BLU_SHIFT; color.rgba[GRN] <<= GRN_SHIFT; color.rgba[RED] <<= RED_SHIFT; // replicate primaries MSBs into LSBs color.rgba[BLU] |= color.rgba[BLU] >> BLU_BITS; color.rgba[GRN] |= color.rgba[GRN] >> GRN_BITS; color.rgba[RED] |= color.rgba[RED] >> RED_BITS; *pcolor = color; } //----------------------------------------------------------------------------- // // DecodeBlockRGB - decompress a color block // //----------------------------------------------------------------------------- void DecodeBlockRGB (DXTBlockRGB *pblockSrc, DXT_COLOR colorDst[DXT_BLOCK_PIXELS]) { int lev; DXT_COLOR clut[4]; PIXBM pixbm; int pixel; int primary; // if source block is invalid, ... if (pblockSrc == NULL) return; // determine the number of color levels in the block lev = (pblockSrc->rgb0 <= pblockSrc->rgb1) ? 2 : 3; // Fill extrema values into pixel code lookup table. RGBToColor(&pblockSrc->rgb0, &clut[0]); RGBToColor(&pblockSrc->rgb1, &clut[1]); clut[0].rgba[ALFA] = clut[1].rgba[ALFA] = clut[2].rgba[ALFA] = 255; if (lev == 3) { // No transparency info present, all color info. ForAllPrimaries { WORD temp0 = clut[0].rgba[primary]; // jvanaken fixed overflow bug WORD temp1 = clut[1].rgba[primary]; clut[2].rgba[primary] = (BYTE)((2*temp0 + temp1 + 1)/3); clut[3].rgba[primary] = (BYTE)((temp0 + 2*temp1 + 1)/3); } clut[3].rgba[ALFA] = 255; } else { // transparency info. ForAllPrimaries { WORD temp0 = clut[0].rgba[primary]; // jvanaken fixed overflow bug WORD temp1 = clut[1].rgba[primary]; clut[2].rgba[primary] = (BYTE)((temp0 + temp1)/2); clut[3].rgba[primary] = 0; // jvanaken added this } clut[3].rgba[ALFA] = 0; } // munge a local copy pixbm = pblockSrc->pixbm; // Look up the actual pixel color in the table. ForAllPixels { // lookup color from pixel bitmap ForAllPrimaries colorDst[pixel].rgba[primary] = clut[pixbm & 3].rgba[primary]; colorDst[pixel].rgba[ALFA] = clut[pixbm & 3].rgba[ALFA]; // prepare to extract next index pixbm >>= 2; } } //----------------------------------------------------------------------------- // DecodeBlockAlpha4 - decompress a block with alpha at 4 BPP //----------------------------------------------------------------------------- void DecodeBlockAlpha4(DXTBlockAlpha4 *pblockSrc, DXT_COLOR colorDst[DXT_BLOCK_PIXELS]) { int row, col; WORD alpha; DecodeBlockRGB(&pblockSrc->rgb, colorDst); for (row = 0; row < 4; ++row) { alpha = pblockSrc->alphabm[row]; for (col = 0; col < 4; ++col) { colorDst[4 * row + col].rgba[ALFA] = ((alpha & 0xf) << 4) | (alpha & 0xf); alpha >>= 4; } } } //----------------------------------------------------------------------------- // // DecodeBlockAlpha3 - decompress a block with alpha at 3 BPP // //----------------------------------------------------------------------------- void DecodeBlockAlpha3(DXTBlockAlpha3 *pblockSrc, DXT_COLOR colorDst[DXT_BLOCK_PIXELS]) { int pixel; int alpha[8]; // alpha lookup table DWORD dwBM = 0; // alpha bitmap in DWORD cache DecodeBlockRGB(&pblockSrc->rgb, colorDst); alpha[0] = pblockSrc->alpha0; alpha[1] = pblockSrc->alpha1; if (alpha[0] > alpha[1]) // 8 alpha ramp { // interpolate intermediate colors alpha[2] = (6 * alpha[0] + 1 * alpha[1]) / 7; alpha[3] = (5 * alpha[0] + 2 * alpha[1]) / 7; alpha[4] = (4 * alpha[0] + 3 * alpha[1]) / 7; alpha[5] = (3 * alpha[0] + 4 * alpha[1]) / 7; alpha[6] = (2 * alpha[0] + 5 * alpha[1]) / 7; alpha[7] = (1 * alpha[0] + 6 * alpha[1]) / 7; } else // else 6 alpha ramp with 0 and 255 { // interpolate intermediate colors alpha[2] = (4 * alpha[0] + 1 * alpha[1]) / 5; alpha[3] = (3 * alpha[0] + 2 * alpha[1]) / 5; alpha[4] = (2 * alpha[0] + 3 * alpha[1]) / 5; alpha[5] = (1 * alpha[0] + 4 * alpha[1]) / 5; alpha[6] = 0; alpha[7] = 255; } ForAllPixels { // reload bitmap dword cache every 8 pixels if ((pixel & 7) == 0) { if (pixel == 0) { // pack 3 bytes into dword dwBM = pblockSrc->alphabm[2]; dwBM <<= 8; dwBM |= pblockSrc->alphabm[1]; dwBM <<= 8; dwBM |= pblockSrc->alphabm[0]; } else // pixel == 8 { // pack 3 bytes into dword dwBM = pblockSrc->alphabm[5]; dwBM <<= 8; dwBM |= pblockSrc->alphabm[4]; dwBM <<= 8; dwBM |= pblockSrc->alphabm[3]; } } // unpack bitmap dword 3 bits at a time colorDst[pixel].rgba[ALFA] = (BYTE)alpha[(dwBM & 7)]; dwBM >>= 3; } } /////////////////////////////////////////////////////////////////////////////// // end