255 lines
7.3 KiB
C++
255 lines
7.3 KiB
C++
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// 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
|