decodePVR2 method

Image? decodePVR2(
  1. List<int> data
)

Implementation

Image? decodePVR2(List<int> data) {
  final length = data.length;

  const HEADER_SIZE = 52;
  const PVRTEX_CUBEMAP = (1 << 12);
  const PVR_PIXELTYPE_MASK = 0xff;
  const PVR_TYPE_RGBA4444 = 0x10;
  const PVR_TYPE_RGBA5551 = 0x11;
  const PVR_TYPE_RGBA8888 = 0x12;
  const PVR_TYPE_RGB565 = 0x13;
  const PVR_TYPE_RGB555 = 0x14;
  const PVR_TYPE_RGB888 = 0x15;
  const PVR_TYPE_I8 = 0x16;
  const PVR_TYPE_AI8 = 0x17;
  const PVR_TYPE_PVRTC2 = 0x18;
  const PVR_TYPE_PVRTC4 = 0x19;

  if (length < HEADER_SIZE) {
    return null;
  }

  final input = InputBuffer(data);
  // Header
  final size = input.readUint32();
  final height = input.readUint32();
  final width = input.readUint32();
  /*int mipcount =*/ input.readUint32();
  final flags = input.readUint32();
  /*int texdatasize =*/ input.readUint32();
  final bpp = input.readUint32();
  /*int rmask =*/ input.readUint32();
  /*int gmask =*/ input.readUint32();
  /*int bmask =*/ input.readUint32();
  final amask = input.readUint32();
  final magic = input.readUint32();
  var numtex = input.readUint32();

  if (size != HEADER_SIZE || magic != 0x21525650) {
    return null;
  }

  if (numtex < 1) {
    numtex = (flags & PVRTEX_CUBEMAP) != 0 ? 6 : 1;
  }

  if (numtex != 1) {
    // only 1 surface supported currently
    return null;
  }

  if (width * height * bpp / 8 > length - HEADER_SIZE) {
    return null;
  }

  final ptype = flags & PVR_PIXELTYPE_MASK;

  switch (ptype) {
    case PVR_TYPE_RGBA4444:
      final image = Image(width, height);
      final out = image.getBytes();
      var oi = 0;
      for (var y = 0; y < height; ++y) {
        for (var x = 0; x < width; ++x) {
          final v1 = input.readByte();
          final v2 = input.readByte();
          final a = (v1 & 0x0f) << 4;
          final b = (v1 & 0xf0);
          final g = (v2 & 0x0f) << 4;
          final r = (v2 & 0xf0);

          out[oi++] = r;
          out[oi++] = g;
          out[oi++] = b;
          out[oi++] = a;
        }
      }
      return image;
    case PVR_TYPE_RGBA5551:
      final image = Image(width, height);
      final out = image.getBytes();
      var oi = 0;
      for (var y = 0; y < height; ++y) {
        for (var x = 0; x < width; ++x) {
          final v = input.readUint16();

          final r = (v & 0xf800) >> 8;
          final g = (v & 0x07c0) >> 3;
          final b = (v & 0x003e) << 2;
          final a = (v & 0x0001) != 0 ? 255 : 0;

          out[oi++] = r;
          out[oi++] = g;
          out[oi++] = b;
          out[oi++] = a;
        }
      }
      return image;
    case PVR_TYPE_RGBA8888:
      final image = Image(width, height);
      final out = image.getBytes();
      var oi = 0;
      for (var y = 0; y < height; ++y) {
        for (var x = 0; x < width; ++x) {
          out[oi++] = input.readByte();
          out[oi++] = input.readByte();
          out[oi++] = input.readByte();
          out[oi++] = input.readByte();
        }
      }
      return image;
    case PVR_TYPE_RGB565:
      final image = Image(width, height);
      final out = image.getBytes();
      var oi = 0;
      for (var y = 0; y < height; ++y) {
        for (var x = 0; x < width; ++x) {
          final v = input.readUint16();
          final b = (v & 0x001f) << 3;
          final g = (v & 0x07e0) >> 3;
          final r = (v & 0xf800) >> 8;
          const a = 255;
          out[oi++] = r;
          out[oi++] = g;
          out[oi++] = b;
          out[oi++] = a;
        }
      }
      return image;
    case PVR_TYPE_RGB555:
      final image = Image(width, height);
      final out = image.getBytes();
      var oi = 0;
      for (var y = 0; y < height; ++y) {
        for (var x = 0; x < width; ++x) {
          final v = input.readUint16();
          final r = (v & 0x001f) << 3;
          final g = (v & 0x03e0) >> 2;
          final b = (v & 0x7c00) >> 7;
          const a = 255;
          out[oi++] = r;
          out[oi++] = g;
          out[oi++] = b;
          out[oi++] = a;
        }
      }
      return image;
    case PVR_TYPE_RGB888:
      final image = Image(width, height);
      final out = image.getBytes();
      var oi = 0;
      for (var y = 0; y < height; ++y) {
        for (var x = 0; x < width; ++x) {
          out[oi++] = input.readByte();
          out[oi++] = input.readByte();
          out[oi++] = input.readByte();
          out[oi++] = 255;
        }
      }
      return image;
    case PVR_TYPE_I8:
      final image = Image(width, height);
      final out = image.getBytes();
      var oi = 0;
      for (var y = 0; y < height; ++y) {
        for (var x = 0; x < width; ++x) {
          final i = input.readByte();
          out[oi++] = i;
          out[oi++] = i;
          out[oi++] = i;
          out[oi++] = 255;
        }
      }
      return image;
    case PVR_TYPE_AI8:
      final image = Image(width, height);
      final out = image.getBytes();
      var oi = 0;
      for (var y = 0; y < height; ++y) {
        for (var x = 0; x < width; ++x) {
          final i = input.readByte();
          final a = input.readByte();
          out[oi++] = i;
          out[oi++] = i;
          out[oi++] = i;
          out[oi++] = a;
        }
      }
      return image;
    case PVR_TYPE_PVRTC2:
      // Currently unsupported
      return null;
    case PVR_TYPE_PVRTC4:
      return amask == 0
          ? decodeRgb4bpp(width, height, input.toUint8List())
          : decodeRgba4bpp(width, height, input.toUint8List());
  }

  // Unknown format
  return null;
}