private byte[] decompressDxt1(TpcTexture texture, ByteArrayInputStream src) throws IOException { int width = texture.getWidth(); int height = texture.getHeight(); int size = width * height * 4; int pitch = width * 4; byte[] dest = new byte[size]; for (int ty = 3; ty < height; ty += 4) { for (int tx = 0; tx < width; tx += 4) { int color0 = readShort(src) & 0xffff; int color1 = readShort(src) & 0xffff; int colors = readInt(src); blended[0] = convert565To8888(color0); blended[1] = convert565To8888(color1); if (color0 > color1) { blended[2] = interpolate32(0.33333333333333333333f, blended[0], blended[1]); blended[3] = interpolate32(0.66666666666666666666f, blended[0], blended[1]); } else { blended[2] = interpolate32(0.5f, blended[0], blended[1]); blended[3] = 0; } int cpx = colors; int blockWidth = Math.min(width, 4); int blockHeight = Math.min(height, 4); for (int y = 0; y < blockHeight; ++y) { for (int x = 0; x < blockWidth; ++x) { int destX = tx + x; int destY = height - 1 - (ty - blockHeight + y); int pixel = blended[cpx & 3]; // System.out.println(destY); cpx >>= 2; if ((destX < width) && (destY < height)) { int offset = destY * pitch + destX * 4; writeBeUInt32(dest, pixel, offset); } } } } } return dest; }
public static void verticalMirror(TpcTexture texture, int recordSize) { for (TpcMipMap mipMap : texture.getMipMaps()) { verticalMirror(mipMap, recordSize); } }
public void convert2RGBA(TpcTexture texture) { if (texture.isCompressed()) { return; } for (TpcMipMap mipMap : texture.getMipMaps()) { if (texture.getFormat() == TpcPixelFormat.RGB) { convertFromRGB2RGBA(mipMap); texture.setDataType(PixelDataType.PixelDataType8); texture.setFormat(TpcPixelFormat.RGBA); texture.setRawFormat(TpcPixelFormatRaw.RGBA8); texture.setMinDataSize(4); } else if (texture.getFormat() == TpcPixelFormat.BGR) { convertFromBgr2RGBA(mipMap); texture.setDataType(PixelDataType.PixelDataType8); texture.setFormat(TpcPixelFormat.RGBA); texture.setRawFormat(TpcPixelFormatRaw.RGBA8); texture.setMinDataSize(4); } else if (texture.getFormat() == TpcPixelFormat.GRAY) { convertFromGRAY2RGBA(mipMap); texture.setDataType(PixelDataType.PixelDataType8); texture.setFormat(TpcPixelFormat.RGBA); texture.setRawFormat(TpcPixelFormatRaw.RGBA8); texture.setMinDataSize(4); } } }
private byte[] decompressDxt5(TpcTexture texture, ByteArrayInputStream src) throws IOException { int width = texture.getWidth(); int height = texture.getHeight(); int size = width * height * 4; int pitch = width * 4; byte[] dest = new byte[size]; for (int ty = height; ty > 0; ty -= 4) { // for (int ty = 3; ty < height; ty += 4) { for (int tx = 0; tx < width; tx += 4) { int alpha0 = readByte(src); int alpha1 = readByte(src); long alphabl = read48LE(src); int color0 = readShort(src) & 0xffff; int color1 = readShort(src) & 0xffff; long colors = little2big(readInt(src)) & 0xffffffffl; alphab[0] = alpha0; alphab[1] = alpha1; if (alpha0 > alpha1) { alphab[2] = (byte) ((6.0f * (double) alphab[0] + 1.0f * (double) alphab[1] + 3.0f) / 7.0f); alphab[3] = (byte) ((5.0f * (double) alphab[0] + 2.0f * (double) alphab[1] + 3.0f) / 7.0f); alphab[4] = (byte) ((4.0f * (double) alphab[0] + 3.0f * (double) alphab[1] + 3.0f) / 7.0f); alphab[5] = (byte) ((3.0f * (double) alphab[0] + 4.0f * (double) alphab[1] + 3.0f) / 7.0f); alphab[6] = (byte) ((2.0f * (double) alphab[0] + 5.0f * (double) alphab[1] + 3.0f) / 7.0f); alphab[7] = (byte) ((1.0f * (double) alphab[0] + 6.0f * (double) alphab[1] + 3.0f) / 7.0f); } else { alphab[2] = (byte) ((4.0f * (double) alphab[0] + 1.0f * (double) alphab[1] + 2.0f) / 5.0f); alphab[3] = (byte) ((3.0f * (double) alphab[0] + 2.0f * (double) alphab[1] + 2.0f) / 5.0f); alphab[4] = (byte) ((2.0f * (double) alphab[0] + 3.0f * (double) alphab[1] + 2.0f) / 5.0f); alphab[5] = (byte) ((1.0f * (double) alphab[0] + 4.0f * (double) alphab[1] + 2.0f) / 5.0f); alphab[6] = 0; alphab[7] = 255; } blended[0] = convert565To8888(color0) & 0xFFFFFF00; blended[1] = convert565To8888(color1) & 0xFFFFFF00; blended[2] = interpolate32(0.333333f, blended[0], blended[1]); blended[3] = interpolate32(0.666666f, blended[0], blended[1]); long cpx = colors; int blockWidth = Math.min(width, 4); int blockHeight = Math.min(height, 4); for (byte y = 0; y < blockHeight; ++y) { for (byte x = 0; x < blockWidth; ++x) { int destX = tx + x; int destY = height - 1 - (ty - blockHeight + y); int alpha = alphab[(int) ((alphabl >> (3 * (4 * (3 - y) + x))) & 7)] & 0xff; long pixel = (blended[(int) (cpx & 3)] | alpha) & 0xffffffffl; cpx >>= 2; if ((destX < width) && (destY < height)) { writeBeUInt32(dest, (int) pixel, destY * pitch + destX * 4); } } } } } return dest; }
public void decompress(TpcTexture texture) throws IOException { if (!texture.isCompressed()) { return; } if (!(texture.getRawFormat() == TpcPixelFormatRaw.DXT1 || texture.getRawFormat() == TpcPixelFormatRaw.DXT3 || texture.getRawFormat() == TpcPixelFormatRaw.DXT5)) { throw new IllegalArgumentException( "Bad compression format " + texture.getRawFormat() + " in texture [" + texture.getName() + "]"); } for (TpcMipMap mipMap : texture.getMipMaps()) { ByteArrayInputStream src = new ByteArrayInputStream(Arrays.copyOf(mipMap.getData(), mipMap.getData().length)); /* The DXT algorithms work on 4x4 pixel blocks. Textures smaller than one * block will be padded, but larger textures need to be correctly aligned. */ byte[] result; if (texture.getRawFormat() == TpcPixelFormatRaw.DXT1) { result = decompressDxt1(texture, src); mipMap.setData(result); mipMap.setSize(mipMap.getWidth() * mipMap.getHeight() * 4); } else if (texture.getRawFormat() == TpcPixelFormatRaw.DXT5) { result = decompressDxt5(texture, src); mipMap.setData(result); mipMap.setSize(mipMap.getWidth() * mipMap.getHeight() * 4); verticalMirror(mipMap, 4); } else if (texture.getRawFormat() == TpcPixelFormatRaw.DXT3) { throw new RuntimeException("DXT3 uncompression is not implemented yet"); } else { throw new RuntimeException("Unknown compression"); } } texture.setCompressed(false); texture.setDataType(PixelDataType.PixelDataType8); texture.setFormat(TpcPixelFormat.RGBA); texture.setRawFormat(TpcPixelFormatRaw.RGBA8); texture.setMinDataSize(4); }