// need the d3d.h for things in format of .dds file #include "StdAfx.h" #include #include #include #include #include "../eterBase/MappedFile.h" #include "../eterBase/Debug.h" #include "DXTCImage.h" struct DXTColBlock { WORD col0; WORD col1; // no bit fields - use bytes BYTE row[4]; }; struct DXTAlphaBlockExplicit { WORD row[4]; }; struct DXTAlphaBlock3BitLinear { BYTE alpha0; BYTE alpha1; BYTE stuff[6]; }; // use cast to struct instead of RGBA_MAKE as struct is much struct Color8888 { BYTE b; // Last one is MSB, 1st is LSB. BYTE g; // order of the output ARGB or BGRA, etc... BYTE r; // change the order of names to change the BYTE a; }; struct Color565 { unsigned nBlue : 5; // order of names changes unsigned nGreen : 6; // byte order of output to 32 bit unsigned nRed : 5; }; ///////////////////////////////////// // should be in ddraw.h #ifndef MAKEFOURCC #define MAKEFOURCC(ch0, ch1, ch2, ch3) \ ((DWORD)(BYTE) (ch0 ) | ((DWORD)(BYTE) (ch1) << 8) | \ ((DWORD)(BYTE) (ch2) << 16) | ((DWORD)(BYTE) (ch3) << 24)) #endif // defined(MAKEFOURCC) CDXTCImage::CDXTCImage() { Initialize(); } CDXTCImage::~CDXTCImage() { } void CDXTCImage::Initialize() { m_nWidth = 0; m_nHeight = 0; for (int i = 0; i < MAX_MIPLEVELS; ++i) m_pbCompBufferByLevels[i] = NULL; } void CDXTCImage::Clear() { for (int i = 0; i < MAX_MIPLEVELS; ++i) m_bCompVector[i].clear(); Initialize(); } bool CDXTCImage::LoadFromFile(const char * filename) { // only understands .dds files for now // return true if success char * exts[] = { ".DDS" }; int next = 1; static char fileupper[MAX_PATH+1]; strncpy(fileupper, filename, MAX_PATH); strupr(fileupper); int i; bool knownformat = false; for (i = 0; i < next; ++i) { char * found = strstr(fileupper, exts[0]); if (found != NULL) { knownformat = true; break; } } if (knownformat == false) { Tracef("Unknown file format encountered! [%s]\n", filename); return(false); } CMappedFile mappedFile; LPCVOID pvMap; if (!mappedFile.Create(filename, &pvMap, 0, 0)) { Tracef("Can't open file for reading! [%s]\n", filename); return false; } return LoadFromMemory((const BYTE*) pvMap); } bool CDXTCImage::LoadHeaderFromMemory(const BYTE * c_pbMap) { ////////////////////////////////////// // start reading the file // from Microsoft's mssdk D3DIM example "Compress" DWORD dwMagic; // Read magic number dwMagic = *(DWORD *) c_pbMap; c_pbMap += sizeof(DWORD); //!@# // if (dwMagic != MAKEFOURCC('D','D','S',' ')) // return false; DDSURFACEDESC2 ddsd; // read from dds file // Read the surface description memcpy(&ddsd, c_pbMap, sizeof(DDSURFACEDESC2)); c_pbMap += sizeof(DDSURFACEDESC2); // Does texture have mipmaps? m_bMipTexture = (ddsd.dwMipMapCount > 0) ? TRUE : FALSE; // Clear unwanted flags // Can't do this!!! surface not re-created here // ddsd.dwFlags &= (~DDSD_PITCH); // ddsd.dwFlags &= (~DDSD_LINEARSIZE); // Is it DXTC ? // I sure hope pixelformat is valid! m_xddPixelFormat.dwFlags = ddsd.ddpfPixelFormat.dwFlags; m_xddPixelFormat.dwFourCC = ddsd.ddpfPixelFormat.dwFourCC; m_xddPixelFormat.dwSize = ddsd.ddpfPixelFormat.dwSize; m_xddPixelFormat.dwRGBBitCount = ddsd.ddpfPixelFormat.dwRGBBitCount; m_xddPixelFormat.dwRGBAlphaBitMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask; m_xddPixelFormat.dwRBitMask = ddsd.ddpfPixelFormat.dwRBitMask; m_xddPixelFormat.dwGBitMask = ddsd.ddpfPixelFormat.dwGBitMask; m_xddPixelFormat.dwBBitMask = ddsd.ddpfPixelFormat.dwBBitMask; DecodePixelFormat(m_strFormat, &m_xddPixelFormat); if (m_CompFormat != PF_DXT1 && m_CompFormat != PF_DXT3 && m_CompFormat != PF_DXT5) { return false; } if (ddsd.dwMipMapCount > MAX_MIPLEVELS) ddsd.dwMipMapCount = MAX_MIPLEVELS; m_nWidth = ddsd.dwWidth; m_nHeight = ddsd.dwHeight; //!@# m_dwMipMapCount = max(1, ddsd.dwMipMapCount); m_dwFlags = ddsd.dwFlags; if (ddsd.dwFlags & DDSD_PITCH) { m_lPitch = ddsd.lPitch; m_pbCompBufferByLevels[0] = c_pbMap; } else { m_lPitch = ddsd.dwLinearSize; if (ddsd.dwFlags & DDSD_MIPMAPCOUNT) { for (DWORD dwLinearSize = ddsd.dwLinearSize, i = 0; i < m_dwMipMapCount; ++i, dwLinearSize >>= 2) { m_pbCompBufferByLevels[i] = c_pbMap; c_pbMap += dwLinearSize; } } else { m_pbCompBufferByLevels[0] = c_pbMap; } } return true; } ////////////////////////////////////////////////////////////////////// bool CDXTCImage::LoadFromMemory(const BYTE * c_pbMap) { if (!LoadHeaderFromMemory(c_pbMap)) return false; if (m_dwFlags & DDSD_PITCH) { DWORD dwBytesPerRow = m_nWidth * m_xddPixelFormat.dwRGBBitCount / 8; m_nCompSize = m_lPitch * m_nHeight; m_nCompLineSz = dwBytesPerRow; m_bCompVector[0].resize(m_nCompSize); BYTE * pDest = &m_bCompVector[0][0]; c_pbMap = m_pbCompBufferByLevels[0]; for (int yp = 0; yp < m_nHeight; ++yp) { memcpy(pDest, c_pbMap, dwBytesPerRow); pDest += m_lPitch; c_pbMap += m_lPitch; } } else { if (m_dwFlags & DDSD_MIPMAPCOUNT) { for (DWORD dwLinearSize = m_lPitch, i = 0; i < m_dwMipMapCount; ++i, dwLinearSize >>= 2) { m_bCompVector[i].resize(dwLinearSize); Copy(i, &m_bCompVector[i][0], dwLinearSize); } } else { m_bCompVector[0].resize(m_lPitch); Copy(0, &m_bCompVector[0][0], m_lPitch); } } // done reading file return true; } bool CDXTCImage::Copy(int miplevel, BYTE * pbDest, long lDestPitch) { if (!(m_dwFlags & DDSD_MIPMAPCOUNT)) if (miplevel) return false; /* DXTColBlock * pBlock; WORD * pPos = (WORD *) &m_pbCompBufferByLevels[miplevel][0]; int xblocks = (m_nWidth >> miplevel) / 4; int yblocks = (m_nHeight >> miplevel) / 4; for (int y = 0; y < yblocks; ++y) { // 8 bytes per block pBlock = (DXTColBlock*) ((DWORD) pPos + y * xblocks * 8); memcpy(pbDest, pBlock, xblocks * 8); pbDest += lDestPitch; } */ memcpy(pbDest, m_pbCompBufferByLevels[miplevel], m_lPitch >> (miplevel * 2)); pbDest += lDestPitch; return true; } void CDXTCImage::Unextract(BYTE * pbDest, int /*iWidth*/, int /*iHeight*/, int iPitch) { if (!m_pbCompBufferByLevels[0]) return; DXTColBlock * pBlock; BYTE * pPos = (BYTE *) &m_pbCompBufferByLevels[0][0]; int xblocks = m_nWidth / 4; int yblocks = (m_nHeight / 4) * ((iPitch / m_nWidth) / 2); for (int y = 0; y < yblocks; ++y) { pBlock = (DXTColBlock*) (pPos + y * xblocks * 8); memcpy(pbDest, pBlock, xblocks * 8); pbDest += xblocks * 8; } /* for (int y = 0; y < iHeight; ++y) { memcpy(pbDest, &m_pbCompBufferByLevels[0][0] + y*iWidth, iWidth); pbDest += iWidth; } */ } void CDXTCImage::Decompress(int miplevel, DWORD * pdwDest) { switch (m_CompFormat) { case PF_DXT1: DecompressDXT1(miplevel, pdwDest); break; case PF_DXT3: DecompressDXT3(miplevel, pdwDest); break; case PF_DXT5: DecompressDXT5(miplevel, pdwDest); break; case PF_ARGB: DecompressARGB(miplevel, pdwDest); break; case PF_UNKNOWN: break; } } inline void GetColorBlockColors(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, Color8888 * col_2, Color8888 * col_3, WORD & wrd) { // There are 4 methods to use - see the Time_ functions. // 1st = shift = does normal approach per byte for color comps // 2nd = use freak variable bit field color565 for component extraction // 3rd = use super-freak DWORD adds BEFORE shifting the color components // This lets you do only 1 add per color instead of 3 BYTE adds and // might be faster // Call RunTimingSession() to run each of them & output result to txt file // freak variable bit structure method // normal math // This method is fastest Color565 * pCol; pCol = (Color565*) & (pBlock->col0); col_0->a = 0xff; col_0->r = pCol->nRed; col_0->r <<= 3; // shift to full precision col_0->g = pCol->nGreen; col_0->g <<= 2; col_0->b = pCol->nBlue; col_0->b <<= 3; pCol = (Color565*) & (pBlock->col1); col_1->a = 0xff; col_1->r = pCol->nRed; col_1->r <<= 3; // shift to full precision col_1->g = pCol->nGreen; col_1->g <<= 2; col_1->b = pCol->nBlue; col_1->b <<= 3; if (pBlock->col0 > pBlock->col1) { // Four-color block: derive the other two colors. // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 // These two bit codes correspond to the 2-bit fields // stored in the 64-bit block. wrd = (WORD) (((WORD) col_0->r * 2 + (WORD) col_1->r) / 3); // no +1 for rounding // as bits have been shifted to 888 col_2->r = (BYTE)wrd; wrd = (WORD) (((WORD) col_0->g * 2 + (WORD) col_1->g) / 3); col_2->g = (BYTE)wrd; wrd = (WORD) (((WORD) col_0->b * 2 + (WORD) col_1->b) / 3); col_2->b = (BYTE)wrd; col_2->a = 0xff; wrd = (WORD) (((WORD) col_0->r + (WORD) col_1->r * 2) / 3); col_3->r = (BYTE)wrd; wrd = (WORD) (((WORD) col_0->g + (WORD) col_1->g * 2) / 3); col_3->g = (BYTE)wrd; wrd = (WORD) (((WORD) col_0->b + (WORD) col_1->b * 2) / 3); col_3->b = (BYTE)wrd; col_3->a = 0xff; } else { // Three-color block: derive the other color. // 00 = color_0, 01 = color_1, 10 = color_2, // 11 = transparent. // These two bit codes correspond to the 2-bit fields // stored in the 64-bit block. // explicit for each component, unlike some refrasts... // Tracef("block has alpha\n"); wrd = (WORD) (((WORD) col_0->r + (WORD) col_1->r) / 2); col_2->r = (BYTE)wrd; wrd = (WORD) (((WORD) col_0->g + (WORD) col_1->g) / 2); col_2->g = (BYTE)wrd; wrd = (WORD) (((WORD) col_0->b + (WORD) col_1->b) / 2); col_2->b = (BYTE)wrd; col_2->a = 0xff; col_3->r = 0x00; // random color to indicate alpha col_3->g = 0x00; col_3->b = 0x00; col_3->a = 0x00; } } // Get color block colors (...) inline void DecodeColorBlock(DWORD * pImPos, DXTColBlock * pColorBlock, int width, DWORD * col_0, DWORD * col_1, DWORD * col_2, DWORD * col_3) { // width is width of image in pixels DWORD bits; int y, n; // bit masks = 00000011, 00001100, 00110000, 11000000 const DWORD masks[] = { 3, 12, 3 << 4, 3 << 6 }; const int shift[] = { 0, 2, 4, 6 }; // r steps through lines in y for (y = 0; y < 4; ++y, pImPos += width - 4) // no width * 4 as DWORD ptr inc will * 4 { // width * 4 bytes per pixel per line // each j dxtc row is 4 lines of pixels // pImPos = (DWORD*) ((DWORD) pBase + i * 16 + (y + j * 4) * m_nWidth * 4); // n steps through pixels for (n = 0; n < 4; ++n) { bits = pColorBlock->row[y] & masks[n]; bits >>= shift[n]; switch (bits) { case 0: *pImPos = *col_0; pImPos++; // increment to next DWORD break; case 1: *pImPos = *col_1; pImPos++; break; case 2: *pImPos = *col_2; pImPos++; break; case 3: *pImPos = *col_3; pImPos++; break; default: Tracef("Your logic is jacked! bits == 0x%x\n", bits); pImPos++; break; } } } } inline void DecodeAlphaExplicit(DWORD * pImPos, DXTAlphaBlockExplicit * pAlphaBlock, int width, DWORD alphazero) { // alphazero is a bit mask that when & with the image color // will zero the alpha bits, so if the image DWORDs are // ARGB then alphazero will be 0x00ffffff or if // RGBA then alphazero will be 0xffffff00 // alphazero constructed automaticaly from field order of Color8888 structure // decodes to 32 bit format only int row, pix; WORD wrd; Color8888 col; col.r = col.g = col.b = 0; //Tracef("\n"); for (row = 0; row < 4; row++, pImPos += width - 4) { // pImPow += pImPos += width-4 moves to next row down wrd = pAlphaBlock->row[row]; // Tracef("0x%.8x\t\t", wrd); for (pix = 0; pix < 4; ++pix) { // zero the alpha bits of image pixel *pImPos &= alphazero; col.a = (BYTE) (wrd & 0x000f); // get only low 4 bits // col.a <<= 4; // shift to full byte precision // NOTE: with just a << 4 you'll never have alpha // of 0xff, 0xf0 is max so pure shift doesn't quite // cover full alpha range. // It's much cheaper than divide & scale though. // To correct for this, and get 0xff for max alpha, // or the low bits back in after left shifting col.a = (BYTE) (col.a | (col.a << 4)); // This allows max 4 bit alpha to be 0xff alpha // in final image, and is crude approach to full // range scale *pImPos |= *((DWORD*)&col); // or the bits into the prev. nulled alpha wrd >>= 4; // move next bits to lowest 4 pImPos++; // move to next pixel in the row } } } static BYTE gBits[4][4]; static WORD gAlphas[8]; static Color8888 gACol[4][4]; inline void DecodeAlpha3BitLinear(DWORD * pImPos, DXTAlphaBlock3BitLinear * pAlphaBlock, int width, DWORD alphazero) { gAlphas[0] = pAlphaBlock->alpha0; gAlphas[1] = pAlphaBlock->alpha1; // 8-alpha or 6-alpha block? if (gAlphas[0] > gAlphas[1]) { // 8-alpha block: derive the other 6 alphas. // 000 = alpha_0, 001 = alpha_1, others are interpolated gAlphas[2] = (WORD) ((6 * gAlphas[0] + gAlphas[1]) / 7); // Bit code 010 gAlphas[3] = (WORD) ((5 * gAlphas[0] + 2 * gAlphas[1]) / 7); // Bit code 011 gAlphas[4] = (WORD) ((4 * gAlphas[0] + 3 * gAlphas[1]) / 7); // Bit code 100 gAlphas[5] = (WORD) ((3 * gAlphas[0] + 4 * gAlphas[1]) / 7); // Bit code 101 gAlphas[6] = (WORD) ((2 * gAlphas[0] + 5 * gAlphas[1]) / 7); // Bit code 110 gAlphas[7] = (WORD) (( gAlphas[0] + 6 * gAlphas[1]) / 7); // Bit code 111 } else { // 6-alpha block: derive the other alphas. // 000 = alpha_0, 001 = alpha_1, others are interpolated gAlphas[2] = (WORD) ((4 * gAlphas[0] + gAlphas[1]) / 5); // Bit code 010 gAlphas[3] = (WORD) ((3 * gAlphas[0] + 2 * gAlphas[1]) / 5); // Bit code 011 gAlphas[4] = (WORD) ((2 * gAlphas[0] + 3 * gAlphas[1]) / 5); // Bit code 100 gAlphas[5] = (WORD) (( gAlphas[0] + 4 * gAlphas[1]) / 5); // Bit code 101 gAlphas[6] = 0; // Bit code 110 gAlphas[7] = 255; // Bit code 111 } // Decode 3-bit fields into array of 16 BYTES with same value // first two rows of 4 pixels each: // pRows = (Alpha3BitRows*) & (pAlphaBlock->stuff[0]); const DWORD mask = 0x00000007; // bits = 00 00 01 11 DWORD bits = *((DWORD*) & (pAlphaBlock->stuff[0])); gBits[0][0] = (BYTE) (bits & mask); bits >>= 3; gBits[0][1] = (BYTE) (bits & mask); bits >>= 3; gBits[0][2] = (BYTE) (bits & mask); bits >>= 3; gBits[0][3] = (BYTE) (bits & mask); bits >>= 3; gBits[1][0] = (BYTE) (bits & mask); bits >>= 3; gBits[1][1] = (BYTE) (bits & mask); bits >>= 3; gBits[1][2] = (BYTE) (bits & mask); bits >>= 3; gBits[1][3] = (BYTE) (bits & mask); // now for last two rows: bits = *((DWORD*) & (pAlphaBlock->stuff[3])); // last 3 bytes gBits[2][0] = (BYTE) (bits & mask); bits >>= 3; gBits[2][1] = (BYTE) (bits & mask); bits >>= 3; gBits[2][2] = (BYTE) (bits & mask); bits >>= 3; gBits[2][3] = (BYTE) (bits & mask); bits >>= 3; gBits[3][0] = (BYTE) (bits & mask); bits >>= 3; gBits[3][1] = (BYTE) (bits & mask); bits >>= 3; gBits[3][2] = (BYTE) (bits & mask); bits >>= 3; gBits[3][3] = (BYTE) (bits & mask); // decode the codes into alpha values int row, pix; for (row = 0; row < 4; ++row) { for (pix = 0; pix < 4; ++pix) { gACol[row][pix].a = (BYTE) gAlphas[gBits[row][pix]]; assert(gACol[row][pix].r == 0); assert(gACol[row][pix].g == 0); assert(gACol[row][pix].b == 0); } } // Write out alpha values to the image bits for (row = 0; row < 4; ++row, pImPos += width - 4) { // pImPow += pImPos += width - 4 moves to next row down for (pix = 0; pix < 4; ++pix) { // zero the alpha bits of image pixel *pImPos &= alphazero; *pImPos |= *((DWORD*) &(gACol[row][pix])); // or the bits into the prev. nulled alpha pImPos++; } } } void CDXTCImage::DecompressDXT1(int miplevel, DWORD * pdwDest) { // This was hacked up pretty quick & slopily // decompresses to 32 bit format 0xARGB int xblocks, yblocks; #ifdef DEBUG if ((ddsd.dwWidth % 4) != 0) { Tracef("****** warning width not div by 4! %d\n", ddsd.dwWidth); } if ((ddsd.dwHeight % 4) != 0) { Tracef("****** warning Height not div by 4! %d\n", ddsd.dwHeight); } Tracef("end check\n"); #endif UINT nWidth = m_nWidth >> miplevel; UINT nHeight = m_nHeight >> miplevel; xblocks = nWidth / 4; yblocks = nHeight / 4; int x, y; DWORD * pBase = (DWORD *) pdwDest; WORD * pPos = (WORD *) &m_bCompVector[miplevel][0];; // pos in compressed data DWORD * pImPos; DXTColBlock * pBlock; Color8888 col_0, col_1, col_2, col_3; WORD wrd; for (y = 0; y < yblocks; ++y) { // 8 bytes per block pBlock = (DXTColBlock *) ((DWORD) pPos + y * xblocks * 8); for (x = 0; x < xblocks; ++x, ++pBlock) { // inline func: GetColorBlockColors(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); pImPos = (DWORD *) ((DWORD) pBase + x*16 + (y*4) * nWidth * 4); DecodeColorBlock(pImPos, pBlock, nWidth, (DWORD *)&col_0, (DWORD *)&col_1, (DWORD *)&col_2, (DWORD *)&col_3); // Set to RGB test pattern // pImPos = (DWORD*) ((DWORD) pBase + i * 4 + j * m_nWidth * 4); // *pImPos = ((i * 4) << 16) | ((j * 4) << 8) | ((63 - i) * 4); // checkerboard of only col_0 and col_1 basis colors: // pImPos = (DWORD *) ((DWORD) pBase + i * 8 + j * m_nWidth * 8); // *pImPos = *((DWORD *) &col_0); // pImPos += 1 + m_nWidth; // *pImPos = *((DWORD *) &col_1); } } } void CDXTCImage::DecompressDXT3(int miplevel, DWORD* pdwDest) { int xblocks, yblocks; #ifdef DEBUG if ((ddsd.dwWidth % 4) != 0) { Tracef("****** warning width not div by 4! %d\n", ddsd.dwWidth); } if ((ddsd.dwHeight % 4) != 0) { Tracef("****** warning Height not div by 4! %d\n", ddsd.dwHeight); } Tracef("end check\n"); #endif UINT nWidth = m_nWidth >> miplevel; UINT nHeight = m_nHeight >> miplevel; xblocks = nWidth / 4; yblocks = nHeight / 4; int x, y; DWORD * pBase = (DWORD *) pdwDest; WORD * pPos = (WORD *) &m_bCompVector[miplevel][0]; // pos in compressed data DWORD * pImPos; // pos in decompressed data DXTColBlock * pBlock; DXTAlphaBlockExplicit * pAlphaBlock; Color8888 col_0, col_1, col_2, col_3; WORD wrd; // fill alphazero with appropriate value to zero out alpha when // alphazero is ANDed with the image color 32 bit DWORD: col_0.a = 0; col_0.r = col_0.g = col_0.b = 0xff; DWORD alphazero = *((DWORD *) &col_0); for (y = 0; y < yblocks; ++y) { // 8 bytes per block // 1 block for alpha, 1 block for color pBlock = (DXTColBlock *) ((DWORD) (pPos + y * xblocks * 16)); for (x = 0; x < xblocks; ++x, ++pBlock) { // inline // Get alpha block pAlphaBlock = (DXTAlphaBlockExplicit *) pBlock; // inline func: // Get color block & colors pBlock++; GetColorBlockColors(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); // Decode the color block into the bitmap bits // inline func: pImPos = (DWORD *) ((DWORD) (pBase + x * 16 + (y * 4) * nWidth * 4)); DecodeColorBlock(pImPos, pBlock, nWidth, (DWORD *) &col_0, (DWORD *) &col_1, (DWORD *) &col_2, (DWORD *) &col_3); // Overwrite the previous alpha bits with the alpha block // info // inline func: DecodeAlphaExplicit(pImPos, pAlphaBlock, nWidth, alphazero); } } } void CDXTCImage::DecompressDXT5(int level, DWORD * pdwDest) { int xblocks, yblocks; #ifdef DEBUG if ((ddsd.dwWidth % 4) != 0) { Tracef("****** warning width not div by 4! %d\n", ddsd.dwWidth); } if ((ddsd.dwHeight % 4) != 0) { Tracef("****** warning Height not div by 4! %d\n", ddsd.dwHeight); } Tracef("end check\n"); #endif UINT nWidth = m_nWidth >> level; UINT nHeight = m_nHeight >> level; xblocks = nWidth / 4; yblocks = nHeight / 4; int x, y; DWORD * pBase = (DWORD *) pdwDest; WORD * pPos = pPos = (WORD *) &m_bCompVector[level][0]; // pos in compressed data DWORD * pImPos; // pos in decompressed data DXTColBlock * pBlock; DXTAlphaBlock3BitLinear * pAlphaBlock; Color8888 col_0, col_1, col_2, col_3; WORD wrd; // fill alphazero with appropriate value to zero out alpha when // alphazero is ANDed with the image color 32 bit DWORD: col_0.a = 0; col_0.r = col_0.g = col_0.b = 0xff; DWORD alphazero = *((DWORD *) &col_0); //////////////////////////////// // Tracef("blocks: x: %d y: %d\n", xblocks, yblocks); for (y = 0; y < yblocks; ++y) { // 8 bytes per block // 1 block for alpha, 1 block for color pBlock = (DXTColBlock*) ((DWORD) (pPos + y * xblocks * 16)); for (x = 0; x < xblocks; ++x, ++pBlock) { // inline // Get alpha block pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; // inline func: // Get color block & colors pBlock++; // Tracef("pBlock: 0x%.8x\n", pBlock); GetColorBlockColors(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); // Decode the color block into the bitmap bits // inline func: pImPos = (DWORD *) ((DWORD) (pBase + x * 16 + (y * 4) * nWidth * 4)); //DecodeColorBlock(pImPos, pBlock, nWidth, (DWORD *)&col_0, (DWORD *)&col_1, (DWORD *)&col_2, (DWORD *)&col_3); DecodeColorBlock(pImPos, pBlock, nWidth, (DWORD *)&col_0, (DWORD *)&col_1, (DWORD *)&col_2, (DWORD *)&col_3); // Overwrite the previous alpha bits with the alpha block // info DecodeAlpha3BitLinear(pImPos, pAlphaBlock, nWidth, alphazero); } } } // dxt5 void CDXTCImage::DecompressARGB(int level, DWORD * pdwDest) { UINT lPitch = m_lPitch >> (level * 2); memcpy(pdwDest, &m_bCompVector[level][0], lPitch); } /* typedef struct _DDSURFACEDESC2 { DWORD dwSize; DWORD dwFlags; DWORD dwHeight; DWORD dwWidth; union { LONG lPitch; DWORD dwLinearSize; } DUMMYUNIONNAMEN(1); DWORD dwBackBufferCount; union { DWORD dwMipMapCount; DWORD dwRefreshRate; } DUMMYUNIONNAMEN(2); DWORD dwAlphaBitDepth; DWORD dwReserved; LPVOID lpSurface; union { DDCOLORKEY ddckCKDestOverlay; DWORD dwEmptyFaceColor; } DUMMYUNIONNAMEN(3); DDCOLORKEY ddckCKDestBlt; DDCOLORKEY ddckCKSrcOverlay; DDCOLORKEY ddckCKSrcBlt; DDPIXELFORMAT ddpfPixelFormat; DDSCAPS2 ddsCaps; DWORD dwTextureStage; } DDSURFACEDESC2, FAR* LPDDSURFACEDESC2; */ //----------------------------------------------------------------------------- // Name: GetNumberOfBits() // Desc: Returns the number of bits set in a DWORD mask // from microsoft mssdk d3dim sample "Compress" //----------------------------------------------------------------------------- static WORD GetNumberOfBits(DWORD dwMask) { WORD wBits; for (wBits = 0; dwMask; wBits++) dwMask = (dwMask & (dwMask - 1)); return wBits; } //----------------------------------------------------------------------------- // Name: PixelFormatToString() // Desc: Creates a string describing a pixel format. // adapted from microsoft mssdk D3DIM Compress example // PixelFormatToString() //----------------------------------------------------------------------------- VOID CDXTCImage::DecodePixelFormat(CHAR* strPixelFormat, XDDPIXELFORMAT* pxddpf) { switch (pxddpf->dwFourCC) { case 0: { // This dds texture isn't compressed so write out ARGB format WORD a = GetNumberOfBits(pxddpf->dwRGBAlphaBitMask); WORD r = GetNumberOfBits(pxddpf->dwRBitMask); WORD g = GetNumberOfBits(pxddpf->dwGBitMask); WORD b = GetNumberOfBits(pxddpf->dwBBitMask); _snprintf(strPixelFormat, 31, "ARGB-%d%d%d%d%s", a, r, g, b, pxddpf->dwBBitMask & DDPF_ALPHAPREMULT ? "-premul" : ""); m_CompFormat = PF_ARGB; } break; case MAKEFOURCC('D','X','T','1'): strncpy(strPixelFormat, "DXT1", 31); m_CompFormat = PF_DXT1; break; case MAKEFOURCC('D','X','T','2'): strncpy(strPixelFormat, "DXT2", 31); m_CompFormat = PF_DXT2; break; case MAKEFOURCC('D','X','T','3'): strncpy(strPixelFormat, "DXT3", 31); m_CompFormat = PF_DXT3; break; case MAKEFOURCC('D','X','T','4'): strncpy(strPixelFormat, "DXT4", 31); m_CompFormat = PF_DXT4; break; case MAKEFOURCC('D','X','T','5'): strncpy(strPixelFormat, "DXT5", 31); m_CompFormat = PF_DXT5; break; default: strcpy(strPixelFormat, "Format Unknown"); m_CompFormat = PF_UNKNOWN; break; } } /* // Struct to hold various timing values struct TimingInfo { LARGE_INTEGER m_start_clk; LARGE_INTEGER m_end_clk; int m_nSamples; LARGE_INTEGER m_interval_sum; // sum of all end-start, nSamples number added in CString m_csName; // text desc of what timed }; void CDXTCImage::RunTimingSession() { // Must have a dxt5 texture loaded // No special reason - just lazy coding // Functions called to time code are separate from non-timed // code. It's alogorithm that counts. ASSERT(m_pCompBytes != NULL); ASSERT(m_pDecompBytes != NULL); // must already have allocated memory switch (m_CompFormat) { case PF_DXT1: case PF_DXT2: case PF_DXT3: case PF_DXT4: case PF_UNKNOWN: Tracef("You must have a DXT5 texture loaded to RunTimingSession()!!\n"); Tracef("Now I will be nasty and ASSERT(false)!\n"); ASSERT(false); break; case PF_DXT5: Tracef("Running code timing session on DXT5 color decompress\n"); break; } LARGE_INTEGER start_clk, end_clk; QueryPerformanceCounter(&start_clk); #define NMETHOD 4 #define NBATCHES 4 int passes[NBATCHES]; passes[0] = 1; passes[1] = 10; passes[2] = 30; passes[3] = 50; TimingInfo method[NMETHOD][NBATCHES]; int i, n; FILE * pf = fopen("timing.txt", "wt"); if (pf == NULL) { return; } fprintf(pf, "\n\n"); for (i = 0; i < NBATCHES; ++i) { Sleep(50); fprintf(pf,"i: %d passes[i]: %d\n", i, passes[i]); Time_Decomp5_01(passes[i], &(method[0][i])); Time_Decomp5_02(passes[i], &(method[1][i])); Time_Decomp5_03(passes[i], &(method[2][i])); Time_Decomp5_04(passes[i], &(method[3][i])); } QueryPerformanceCounter(&end_clk); // unsigned long total; // total = (unsigned long) (end_clk - start_clk); LARGE_INTEGER freq; QueryPerformanceFrequency(& freq); fprintf(pf, "\nCounter freq = %u %d \n", freq.LowPart, freq.HighPart); fprintf(pf, "start: %u %u end: %u %u\n", start_clk.LowPart, start_clk.HighPart, end_clk.LowPart, end_clk.HighPart); Tracef("\nCounter freq = %u %d \n", freq.LowPart, freq.HighPart); Tracef("start: %u %u end: %u %u\n", start_clk.LowPart, start_clk.HighPart, end_clk.LowPart, end_clk.HighPart); double dur = ((double)end_clk.LowPart - (double)start_clk.LowPart) / (double)freq.LowPart; fprintf(pf, "Total timing session took: %u cycles = %f seconds\n", (end_clk.LowPart - start_clk.LowPart), dur); fprintf(pf, "\n\n"); Tracef("Total timing session took: %u cycles = %f seconds\n", (end_clk.LowPart - start_clk.LowPart), dur); Tracef("\n\n"); for (n = 0; n < NMETHOD; ++n) { for (i = 0; i < NBATCHES; ++i) { fprintf(pf, "method %d:\n", n); fprintf(pf, " %s", method[n][i].m_csName); fprintf(pf, " tot: %u %u\n", method[n][i].m_interval_sum.HighPart, method[n][i].m_interval_sum.LowPart); Tracef("method %d:\n", n); Tracef(" %s", method[n][i].m_csName); Tracef(" tot: %u %u\n", method[n][i].m_interval_sum.HighPart, method[n][i].m_interval_sum.LowPart); dur = ((double)method[n][i].m_interval_sum.LowPart) / ((double)method[n][i].m_nSamples * (double)freq.LowPart); fprintf(pf, " avg: %u\n", method[n][i].m_interval_sum.LowPart / method[n][i].m_nSamples); fprintf(pf, " avg time: %f sec\n", dur); Tracef(" avg: %u\n", method[n][i].m_interval_sum.LowPart / method[n][i].m_nSamples); Tracef(" avg time: %f sec\n", dur); } fprintf(pf, "\n\n"); Tracef("\n\n"); } fclose(pf); MessageBeep(MB_OK); //BOOL QueryPerformanceFrequency( // LARGE_INTEGER *lpFrequency // address of current frequency //); } inline void GetColorBlockColors_m2(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, Color8888 * col_2, Color8888 * col_3, WORD & wrd ) { // method 2 // freak variable bit structure method // normal math Color565 * pCol; pCol = (Color565*) & (pBlock->col0); col_0->a = 0xff; col_0->r = pCol->nRed; col_0->r <<= 3; // shift to full precision col_0->g = pCol->nGreen; col_0->g <<= 2; col_0->b = pCol->nBlue; col_0->b <<= 3; pCol = (Color565*) & (pBlock->col1); col_1->a = 0xff; col_1->r = pCol->nRed; col_1->r <<= 3; // shift to full precision col_1->g = pCol->nGreen; col_1->g <<= 2; col_1->b = pCol->nBlue; col_1->b <<= 3; if (pBlock->col0 > pBlock->col1) { // Four-color block: derive the other two colors. // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 // These two bit codes correspond to the 2-bit fields // stored in the 64-bit block. wrd = ((WORD) col_0->r * 2 + (WORD) col_1->r) / 3; // no +1 for rounding // as bits have been shifted to 888 col_2->r = (BYTE)wrd; wrd = ((WORD) col_0->g * 2 + (WORD) col_1->g) / 3; col_2->g = (BYTE)wrd; wrd = ((WORD) col_0->b * 2 + (WORD) col_1->b) / 3; col_2->b = (BYTE)wrd; col_2->a = 0xff; wrd = ((WORD) col_0->r + (WORD) col_1->r * 2) / 3; col_3->r = (BYTE)wrd; wrd = ((WORD) col_0->g + (WORD) col_1->g * 2) / 3; col_3->g = (BYTE)wrd; wrd = ((WORD) col_0->b + (WORD) col_1->b * 2) / 3; col_3->b = (BYTE)wrd; col_3->a = 0xff; } else { // Three-color block: derive the other color. // 00 = color_0, 01 = color_1, 10 = color_2, // 11 = transparent. // These two bit codes correspond to the 2-bit fields // stored in the 64-bit block. // explicit for each component, unlike some refrasts... // Tracef("block has alpha\n"); wrd = ((WORD) col_0->r + (WORD) col_1->r) / 2; col_2->r = (BYTE)wrd; wrd = ((WORD) col_0->g + (WORD) col_1->g) / 2; col_2->g = (BYTE)wrd; wrd = ((WORD) col_0->b + (WORD) col_1->b) / 2; col_2->b = (BYTE)wrd; col_2->a = 0xff; col_3->r = 0x00; // random color to indicate alpha col_3->g = 0xff; col_3->b = 0xff; col_3->a = 0x00; } } inline void GetColorBlockColors_m3(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, Color8888 * col_2, Color8888 * col_3, WORD & wrd ) { // method 3 ////////////////////////////////////////////////////// // super-freak variable bit structure with // Cool Math Trick (tm) // Do 2/3 1/3 math BEFORE bit shift on the whole DWORD // as the fields will NEVER carry into the next // or overflow!! =) Color565 * pCol; pCol = (Color565*) & (pBlock->col0); col_0->a = 0x00; // must set to 0 to avoid overflow in DWORD add col_0->r = pCol->nRed; col_0->g = pCol->nGreen; col_0->b = pCol->nBlue; pCol = (Color565*) & (pBlock->col1); col_1->a = 0x00; col_1->r = pCol->nRed; col_1->g = pCol->nGreen; col_1->b = pCol->nBlue; if (pBlock->col0 > pBlock->col1) { *((DWORD*)col_2) = ((*((DWORD*)col_0)) * 2 + (*((DWORD*)col_1))); *((DWORD*)col_3) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1)) * 2); // now shift to appropriate precision & divide by 3. col_2->r = ((WORD) col_2->r << 3) / (WORD)3; col_2->g = ((WORD) col_2->g << 2) / (WORD)3; col_2->b = ((WORD) col_2->b << 3) / (WORD)3; col_3->r = ((WORD) col_3->r << 3) / (WORD)3; col_3->g = ((WORD) col_3->g << 2) / (WORD)3; col_3->b = ((WORD) col_3->b << 3) / (WORD)3; col_0->a = 0xff; // now set appropriate alpha col_1->a = 0xff; col_2->a = 0xff; col_3->a = 0xff; } else { *((DWORD*)col_2) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1))); // now shift to appropriate precision & divide by 2. // << 3) / 2 == << 2 // << 2) / 2 == << 1 col_2->r = ((WORD) col_2->r << 2); col_2->g = ((WORD) col_2->g << 1); col_2->b = ((WORD) col_2->b << 2); col_2->a = 0xff; col_3->a = 0x00; // col_3->r = 0x00; // random color to indicate alpha col_3->g = 0xff; col_3->b = 0xff; } // now shift orig color components col_0->r <<= 3; col_0->g <<= 2; col_0->b <<= 3; col_1->r <<= 3; col_1->g <<= 2; col_1->b <<= 3; } inline void GetColorBlockColors_m4(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, Color8888 * col_2, Color8888 * col_3, WORD & wrd ) { // m1 color extraction from 5-6-5 // m3 color math on DWORD before bit shift to full precision wrd = pBlock->col0; col_0->a = 0x00; // must set to 0 to avoid possible overflow & carry to next field in DWORD add // extract r,g,b bits col_0->b = (unsigned char) wrd & 0x1f; // 0x1f = 0001 1111 to mask out upper 3 bits wrd >>= 5; col_0->g = (unsigned char) wrd & 0x3f; // 0x3f = 0011 1111 to mask out upper 2 bits wrd >>= 6; col_0->r = (unsigned char) wrd & 0x1f; // same for col # 2: wrd = pBlock->col1; col_1->a = 0x00; // must set to 0 to avoid possible overflow in DWORD add // extract r,g,b bits col_1->b = (unsigned char) wrd & 0x1f; wrd >>= 5; col_1->g = (unsigned char) wrd & 0x3f; wrd >>= 6; col_1->r = (unsigned char) wrd & 0x1f; if (pBlock->col0 > pBlock->col1) { *((DWORD*)col_2) = ((*((DWORD*)col_0)) * 2 + (*((DWORD*)col_1))); *((DWORD*)col_3) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1)) * 2); // shift to appropriate precision & divide by 3. col_2->r = ((WORD) col_2->r << 3) / (WORD)3; col_2->g = ((WORD) col_2->g << 2) / (WORD)3; col_2->b = ((WORD) col_2->b << 3) / (WORD)3; col_3->r = ((WORD) col_3->r << 3) / (WORD)3; col_3->g = ((WORD) col_3->g << 2) / (WORD)3; col_3->b = ((WORD) col_3->b << 3) / (WORD)3; col_0->a = 0xff; // set appropriate alpha col_1->a = 0xff; col_2->a = 0xff; col_3->a = 0xff; } else { *((DWORD*)col_2) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1))); // shift to appropriate precision & divide by 2. // << 3) / 2 == << 2 // << 2) / 2 == << 1 col_2->r = ((WORD) col_2->r << 2); col_2->g = ((WORD) col_2->g << 1); col_2->b = ((WORD) col_2->b << 2); col_2->a = 0xff; col_3->a = 0x00; // col_3->r = 0x00; // random color to indicate alpha col_3->g = 0xff; col_3->b = 0xff; } // shift orig color components to full precision col_0->r <<= 3; col_0->g <<= 2; col_0->b <<= 3; col_1->r <<= 3; col_1->g <<= 2; col_1->b <<= 3; } inline void GetColorBlockColors_m1(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, Color8888 * col_2, Color8888 * col_3, WORD & wrd ) { // Method 1: // Shifty method wrd = pBlock->col0; col_0->a = 0xff; // extract r,g,b bits col_0->b = (unsigned char) wrd; col_0->b <<= 3; // shift to full precision wrd >>= 5; col_0->g = (unsigned char) wrd; col_0->g <<= 2; // shift to full precision wrd >>= 6; col_0->r = (unsigned char) wrd; col_0->r <<= 3; // shift to full precision // same for col # 2: wrd = pBlock->col1; col_1->a = 0xff; // extract r,g,b bits col_1->b = (unsigned char) wrd; col_1->b <<= 3; // shift to full precision wrd >>= 5; col_1->g = (unsigned char) wrd; col_1->g <<= 2; // shift to full precision wrd >>= 6; col_1->r = (unsigned char) wrd; col_1->r <<= 3; // shift to full precision // use this for all but the super-freak math method if (pBlock->col0 > pBlock->col1) { // Four-color block: derive the other two colors. // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 // These two bit codes correspond to the 2-bit fields // stored in the 64-bit block. wrd = ((WORD) col_0->r * 2 + (WORD) col_1->r) / 3; // no +1 for rounding // as bits have been shifted to 888 col_2->r = (BYTE)wrd; wrd = ((WORD) col_0->g * 2 + (WORD) col_1->g) / 3; col_2->g = (BYTE)wrd; wrd = ((WORD) col_0->b * 2 + (WORD) col_1->b) / 3; col_2->b = (BYTE)wrd; col_2->a = 0xff; wrd = ((WORD) col_0->r + (WORD) col_1->r * 2) / 3; col_3->r = (BYTE)wrd; wrd = ((WORD) col_0->g + (WORD) col_1->g * 2) / 3; col_3->g = (BYTE)wrd; wrd = ((WORD) col_0->b + (WORD) col_1->b * 2) / 3; col_3->b = (BYTE)wrd; col_3->a = 0xff; } else { // Three-color block: derive the other color. // 00 = color_0, 01 = color_1, 10 = color_2, // 11 = transparent. // These two bit codes correspond to the 2-bit fields // stored in the 64-bit block. // explicit for each component, unlike some refrasts... // Tracef("block has alpha\n"); wrd = ((WORD) col_0->r + (WORD) col_1->r) / 2; col_2->r = (BYTE)wrd; wrd = ((WORD) col_0->g + (WORD) col_1->g) / 2; col_2->g = (BYTE)wrd; wrd = ((WORD) col_0->b + (WORD) col_1->b) / 2; col_2->b = (BYTE)wrd; col_2->a = 0xff; col_3->r = 0x00; // random color to indicate alpha col_3->g = 0xff; col_3->b = 0xff; col_3->a = 0x00; } } // Get color block colors (...) void CDXTCImage::Time_Decomp5_01(int ntimes, TimingInfo * info) { int n; info->m_nSamples = 0; info->m_interval_sum.QuadPart = 0; info->m_csName.Format("Timing decomp method 1: bit shift, for %d times\n", ntimes); for (n = 0; n < ntimes; n++) { QueryPerformanceCounter(& info->m_start_clk); int xblocks, yblocks; xblocks = m_DDSD.dwWidth / 4; yblocks = m_DDSD.dwHeight / 4; int i,j; DWORD * pBase = (DWORD*) m_pDecompBytes; DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data DXTColBlock * pBlock; DXTAlphaBlock3BitLinear * pAlphaBlock; Color8888 col_0, col_1, col_2, col_3; WORD wrd; // fill alphazero with appropriate value to zero out alpha when // alphazero is ANDed with the image color 32 bit DWORD: col_0.a = 0; col_0.r = col_0.g = col_0.b = 0xff; DWORD alphazero = *((DWORD*) &col_0); // ** See DecompressDXT5 code for comments!! for (j = 0; j < yblocks; ++j) { pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16); for (i = 0; i < xblocks; ++i, ++pBlock) { pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; pBlock++; GetColorBlockColors_m1(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4); DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1, (DWORD*)&col_2, (DWORD*)&col_3); DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero); } } QueryPerformanceCounter(& info->m_end_clk); info->m_nSamples ++; info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart; } } void CDXTCImage::Time_Decomp5_02(int ntimes, TimingInfo * info) { int n; info->m_nSamples = 0; info->m_interval_sum.QuadPart = 0; info->m_csName.Format("Timing decomp method 2: bit field struct, for %d times\n", ntimes); for (n = 0; n < ntimes; n++) { QueryPerformanceCounter(& info->m_start_clk); int xblocks, yblocks; xblocks = m_DDSD.dwWidth / 4; yblocks = m_DDSD.dwHeight / 4; int i,j; DWORD * pBase = (DWORD*) m_pDecompBytes; DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data DXTColBlock * pBlock; DXTAlphaBlock3BitLinear * pAlphaBlock; Color8888 col_0, col_1, col_2, col_3; WORD wrd; // fill alphazero with appropriate value to zero out alpha when // alphazero is ANDed with the image color 32 bit DWORD: col_0.a = 0; col_0.r = col_0.g = col_0.b = 0xff; DWORD alphazero = *((DWORD*) &col_0); // ** See DecompressDXT5 code for comments!! for (j = 0; j < yblocks; ++j) { pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16); for (i = 0; i < xblocks; ++i, ++pBlock) { pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; pBlock++; GetColorBlockColors_m2(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4); DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1, (DWORD*)&col_2, (DWORD*)&col_3); DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero); } } QueryPerformanceCounter(& info->m_end_clk); info->m_nSamples ++; info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart; } } void CDXTCImage::Time_Decomp5_03(int ntimes, TimingInfo * info) { int n; info->m_nSamples = 0; info->m_interval_sum.QuadPart = 0; info->m_csName.Format("Timing decomp method 3: bit field struct w/ pre-shift math, for %d times\n", ntimes); for (n = 0; n < ntimes; n++) { QueryPerformanceCounter(& info->m_start_clk); int xblocks, yblocks; xblocks = m_DDSD.dwWidth / 4; yblocks = m_DDSD.dwHeight / 4; int i,j; DWORD * pBase = (DWORD*) m_pDecompBytes; DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data DXTColBlock * pBlock; DXTAlphaBlock3BitLinear * pAlphaBlock; Color8888 col_0, col_1, col_2, col_3; WORD wrd; // fill alphazero with appropriate value to zero out alpha when // alphazero is ANDed with the image color 32 bit DWORD: col_0.a = 0; col_0.r = col_0.g = col_0.b = 0xff; DWORD alphazero = *((DWORD*) &col_0); // ** See DecompressDXT5 code for comments!! for (j = 0; j < yblocks; ++j) { pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16); for (i = 0; i < xblocks; ++i, ++pBlock) { pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; pBlock++; GetColorBlockColors_m3(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4); DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1, (DWORD*)&col_2, (DWORD*)&col_3); DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero); } } QueryPerformanceCounter(& info->m_end_clk); info->m_nSamples ++; info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart; } } void CDXTCImage::Time_Decomp5_04(int ntimes, TimingInfo * info) { int n; info->m_nSamples = 0; info->m_interval_sum.QuadPart = 0; info->m_csName.Format("Timing decomp method 4: shift extract w/ pre-shift math, for %d times\n", ntimes); QueryPerformanceCounter(& info->m_start_clk); for (n = 0; n < ntimes; n++) { int xblocks, yblocks; xblocks = m_DDSD.dwWidth / 4; yblocks = m_DDSD.dwHeight / 4; int i,j; DWORD * pBase = (DWORD*) m_pDecompBytes; DWORD * pImPos = (DWORD*) pBase; // pos in decompressed data WORD * pPos = (WORD*) m_pCompBytes; // pos in compressed data DXTColBlock * pBlock; DXTAlphaBlock3BitLinear * pAlphaBlock; Color8888 col_0, col_1, col_2, col_3; WORD wrd; // fill alphazero with appropriate value to zero out alpha when // alphazero is ANDed with the image color 32 bit DWORD: col_0.a = 0; col_0.r = col_0.g = col_0.b = 0xff; DWORD alphazero = *((DWORD*) &col_0); // ** See DecompressDXT5 code for comments!! for (j = 0; j < yblocks; ++j) { pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16); for (i = 0; i < xblocks; ++i, ++pBlock) { pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock; pBlock++; GetColorBlockColors_m4(pBlock, &col_0, &col_1, &col_2, &col_3, wrd); pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4); DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1, (DWORD*)&col_2, (DWORD*)&col_3); DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero); } } } QueryPerformanceCounter(& info->m_end_clk); info->m_nSamples = ntimes; info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart; } */