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);
  }