private BufferedImage decodeDxt3Buffer() { int numBlocksWide = width / BLOCK_SIZE; int numBlocksHigh = height / BLOCK_SIZE; // always at least 1x1 tile numBlocksWide = numBlocksWide < 1 ? 1 : numBlocksWide; numBlocksHigh = numBlocksHigh < 1 ? 1 : numBlocksHigh; int blockWidth = Math.min(width, BLOCK_SIZE); int blockHeight = Math.min(height, BLOCK_SIZE); int[] pixels = new int[blockWidth * blockHeight]; BufferedImage delegate = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // One copy of table to minimises new calls Color24[] table = new Color24[4]; table[0] = new Color24(); table[1] = new Color24(); table[2] = new Color24(); table[3] = new Color24(); for (int row = 0; row < numBlocksHigh; row++) { for (int col = 0; col < numBlocksWide; col++) { long alphaData = buffer.getLong(); short minColor = buffer.getShort(); short maxColor = buffer.getShort(); int colorIndexMask = buffer.getInt(); Color24[] lookupTable = Color24.expandLookupTable(table, minColor, maxColor); for (int br = 0; br < blockHeight; br++) { for (int bc = 0; bc < blockWidth; bc++) { int k = (br * blockWidth) + bc; int alpha = (int) (alphaData >>> (k * 4)) & 0xF; // Alphas are just 4 bits per pixel alpha <<= 4; int colorIndex = (colorIndexMask >>> k * 2) & 0x03; Color24 color = lookupTable[colorIndex]; int pixel8888 = (alpha << 24) | color.pix888; // for yUp must flip it , so NOT pixels[br * blockWidth + bc] = pixel8888; pixels[((blockHeight - 1) - br) * blockWidth + bc] = pixel8888; } } // notice vertical flipping there delegate.setRGB( col * blockWidth, (height - blockHeight) - (row * blockHeight), blockWidth, blockHeight, pixels, 0, blockWidth); } } return delegate; }
private BufferedImage decompressRGBA_S3TC_DXT5_EXT() { int numBlocksWide = width / BLOCK_SIZE; int numBlocksHigh = height / BLOCK_SIZE; // always at least 1x1 tile numBlocksWide = numBlocksWide < 1 ? 1 : numBlocksWide; numBlocksHigh = numBlocksHigh < 1 ? 1 : numBlocksHigh; int blockWidth = Math.min(width, BLOCK_SIZE); int blockHeight = Math.min(height, BLOCK_SIZE); int[] pixels = new int[blockWidth * blockHeight]; BufferedImage delegate = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // One copy of table to minimises new calls Color24[] table = new Color24[4]; table[0] = new Color24(); table[1] = new Color24(); table[2] = new Color24(); table[3] = new Color24(); for (int row = 0; row < numBlocksHigh; row++) { for (int col = 0; col < numBlocksWide; col++) { int alpha0 = buffer.get() & 0xff; // unsigned byte int alpha1 = buffer.get() & 0xff; // unsigned byte // next 6 bytes are a look up list (note long casts, important!) long alphaBits = (buffer.get() & 0xffL) << 0L // | (buffer.get() & 0xffL) << 8L // | (buffer.get() & 0xffL) << 16L // | (buffer.get() & 0xffL) << 24L // | (buffer.get() & 0xffL) << 32L // | (buffer.get() & 0xffL) << 40L; // short minColor = buffer.getShort(); short maxColor = buffer.getShort(); int colorIndexMask = buffer.getInt(); Color24[] lookupTable = Color24.expandLookupTable(table, minColor, maxColor); for (int br = 0; br < blockHeight; br++) { for (int bc = 0; bc < blockWidth; bc++) { int k = (br * blockWidth) + bc; int alphaCode = (int) (alphaBits >> (3 * k) & 0x07); // bottom 3 bits int alpha = 0; if (alphaCode == 0) { alpha = alpha0; } else if (alphaCode == 1) { alpha = alpha1; } else if (alpha0 > alpha1) { alpha = ((8 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 7; } else { if (alphaCode == 6) alpha = 0; else if (alphaCode == 7) alpha = 255; else alpha = ((6 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 5; } int colorIndex = (colorIndexMask >>> k * 2) & 0x03; Color24 color = lookupTable[colorIndex]; int pixel8888 = (alpha << 24) | color.pix888; // for yUp must flip it , so NOT pixels[br * blockWidth + bc] = pixel8888; pixels[((blockHeight - 1) - br) * blockWidth + bc] = pixel8888; } } // notice vertical flipping there delegate.setRGB( col * blockWidth, (height - blockHeight) - (row * blockHeight), blockWidth, blockHeight, pixels, 0, blockWidth); } } return delegate; }
private BufferedImage decodeDxt1Buffer() { int numBlocksWide = width / BLOCK_SIZE; int numBlocksHigh = height / BLOCK_SIZE; // always at least 1x1 tile numBlocksWide = numBlocksWide < 1 ? 1 : numBlocksWide; numBlocksHigh = numBlocksHigh < 1 ? 1 : numBlocksHigh; int blockWidth = Math.min(width, BLOCK_SIZE); int blockHeight = Math.min(height, BLOCK_SIZE); int[] pixels = new int[blockWidth * blockHeight]; BufferedImage delegate = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // One copy of table to minimises new calls Color24[] table = new Color24[4]; table[0] = new Color24(); table[1] = new Color24(); table[2] = new Color24(); table[3] = new Color24(); for (int row = 0; row < numBlocksHigh; row++) { for (int col = 0; col < numBlocksWide; col++) { short c0 = buffer.getShort(); short c1 = buffer.getShort(); int colorIndexMask = buffer.getInt(); // http://en.wikipedia.org/wiki/S3_Texture_Compression if (ignoreAlpha || !Color24.hasAlphaBit(c0, c1)) { Color24[] lookupTable = Color24.expandLookupTable(table, c0, c1); for (int br = 0; br < blockHeight; br++) { for (int bc = 0; bc < blockWidth; bc++) { int k = (br * blockWidth) + bc; int colorIndex = (colorIndexMask >>> k * 2) & 0x03; // for yUp must flip it so NOT pixels[br * blockWidth + bc] = (0xFF << 24) | // lookupTable[colorIndex].pix888; pixels[((blockHeight - 1) - br) * blockWidth + bc] = (0xFF << 24) | lookupTable[colorIndex].pix888; } } } else { Color24[] lookupTable = Color24.expandLookupTableAlphable(table, c0, c1); for (int br = 0; br < blockHeight; br++) { for (int bc = 0; bc < blockWidth; bc++) { int k = (br * blockWidth) + bc; int colorIndex = (colorIndexMask >>> k * 2) & 0x03; int alpha = (colorIndex == 3) ? 0x00 : 0xFF; // for yUp must flip it , so NOT pixels[br * blockWidth + bc] = (alpha << 24) | // lookupTable[colorIndex].pix888; pixels[((blockHeight - 1) - br) * blockWidth + bc] = (alpha << 24) | lookupTable[colorIndex].pix888; } } } delegate.setRGB( col * blockWidth, (height - blockHeight) - (row * blockHeight), blockWidth, blockHeight, pixels, 0, blockWidth); } } return delegate; }