encodeRgb4bpp method
Implementation
Uint8List encodeRgb4bpp(Image bitmap) {
if (bitmap.width != bitmap.height) {
throw ImageException('PVRTC requires a square image.');
}
if (!PvrBitUtility.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;
// Allocate enough data for encoding the image.
final outputData = Uint8List((bitmap.width * bitmap.height) ~/ 2);
final packet = PvrPacket(outputData);
final p0 = PvrPacket(outputData);
final p1 = PvrPacket(outputData);
final p2 = PvrPacket(outputData);
final p3 = PvrPacket(outputData);
for (var y = 0; y < blocks; ++y) {
for (var x = 0; x < blocks; ++x) {
final cbb = _calculateBoundingBoxRgb(bitmap, x, y);
packet
..setBlock(x, y)
..usePunchthroughAlpha = false
..setColorRgbA(cbb.min as PvrColorRgb)
..setColorRgbB(cbb.max as PvrColorRgb);
}
}
const factors = PvrPacket.bilinearFactors;
for (var y = 0, y4 = 0; y < blocks; ++y, y4 += 4) {
for (var x = 0, x4 = 0; x < blocks; ++x, x4 += 4) {
var factorIndex = 0;
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.getColorRgbA() * factors[factorIndex][0] +
p1.getColorRgbA() * factors[factorIndex][1] +
p2.getColorRgbA() * factors[factorIndex][2] +
p3.getColorRgbA() * factors[factorIndex][3];
final cb = p0.getColorRgbB() * factors[factorIndex][0] +
p1.getColorRgbB() * factors[factorIndex][1] +
p2.getColorRgbB() * factors[factorIndex][2] +
p3.getColorRgbB() * factors[factorIndex][3];
//final pi = pixelIndex + ((py * size + px) * 4);
final pi = bitmap.getPixel(x4 + px, y4 + py);
final r = pi.r.toInt();
final g = pi.g.toInt();
final b = pi.b.toInt();
final d = cb - ca;
final p = PvrColorRgb(r * 16, g * 16, b * 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 = PvrBitUtility.rotateRight(modulationData, 2);
factorIndex++;
}
}
packet
..setBlock(x, y)
..modulationData = modulationData;
}
}
return outputData;
}