encodeRgba4Bpp method
Implementation
Uint8List encodeRgba4Bpp(Image bitmap) {
if (bitmap.width != bitmap.height) {
throw ImageException('PVRTC requires a square image.');
}
if (!BitUtility.isPowerOf2(bitmap.width)) {
throw ImageException('PVRTC requires a power-of-two sized image.');
}
final size = bitmap.width;
final blocks = size ~/ 4;
final blockMask = blocks - 1;
final bitmapData = bitmap.getBytes();
// Allocate enough data for encoding the image.
final outputData = Uint8List((bitmap.width * bitmap.height) ~/ 2);
final packet = PvrtcPacket(outputData);
final p0 = PvrtcPacket(outputData);
final p1 = PvrtcPacket(outputData);
final p2 = PvrtcPacket(outputData);
final p3 = PvrtcPacket(outputData);
for (var y = 0; y < blocks; ++y) {
for (var x = 0; x < blocks; ++x) {
packet.setBlock(x, y);
packet.usePunchthroughAlpha = 0;
final cbb = _calculateBoundingBoxRgba(bitmap, x, y);
packet.setColorRgbaA(cbb.min as PvrtcColorRgba);
packet.setColorRgbaB(cbb.max as PvrtcColorRgba);
}
}
const factors = PvrtcPacket.BILINEAR_FACTORS;
for (var y = 0; y < blocks; ++y) {
for (var x = 0; x < blocks; ++x) {
var factorIndex = 0;
final pixelIndex = (y * 4 * size + x * 4) * 4;
var modulationData = 0;
for (var py = 0; py < 4; ++py) {
final yOffset = (py < 2) ? -1 : 0;
final y0 = (y + yOffset) & blockMask;
final y1 = (y0 + 1) & blockMask;
for (var px = 0; px < 4; ++px) {
final xOffset = (px < 2) ? -1 : 0;
final x0 = (x + xOffset) & blockMask;
final x1 = (x0 + 1) & blockMask;
p0.setBlock(x0, y0);
p1.setBlock(x1, y0);
p2.setBlock(x0, y1);
p3.setBlock(x1, y1);
final ca = p0.getColorRgbaA() * factors[factorIndex][0] +
p1.getColorRgbaA() * factors[factorIndex][1] +
p2.getColorRgbaA() * factors[factorIndex][2] +
p3.getColorRgbaA() * factors[factorIndex][3];
final cb = p0.getColorRgbaB() * factors[factorIndex][0] +
p1.getColorRgbaB() * factors[factorIndex][1] +
p2.getColorRgbaB() * factors[factorIndex][2] +
p3.getColorRgbaB() * factors[factorIndex][3];
final pi = pixelIndex + ((py * size + px) * 4);
final r = bitmapData[pi];
final g = bitmapData[pi + 1];
final b = bitmapData[pi + 2];
final a = bitmapData[pi + 3];
final d = cb - ca;
final p = PvrtcColorRgba(r * 16, g * 16, b * 16, a * 16);
final v = p - ca;
// PVRTC uses weightings of 0, 3/8, 5/8 and 1
// The boundaries for these are 3/16, 1/2 (=8/16), 13/16
final projection = v.dotProd(d) * 16;
final lengthSquared = d.dotProd(d);
if (projection > 3 * lengthSquared) {
modulationData++;
}
if (projection > 8 * lengthSquared) {
modulationData++;
}
if (projection > 13 * lengthSquared) {
modulationData++;
}
modulationData = BitUtility.rotateRight(modulationData, 2);
factorIndex++;
}
}
packet.setBlock(x, y);
packet.modulationData = modulationData;
}
}
return outputData;
}