private static Bitmap UncompressATI2(byte[] imgData, int w, int h)
{
const int bufferSize = 16;
const int bytesPerPixel = 3;
byte[] blockStorage = new byte[bufferSize];
MemoryStream bitmapStream = new MemoryStream(w * h * 2);
int ptr = 0;
for (int s = 0; s < h; s += 4)
{
for (int t = 0; t < w; t += 4)
{
Buffer.BlockCopy(imgData, ptr, blockStorage, 0, bufferSize);
ptr += bufferSize;
#region Block Decompression Loop
byte[][] rgbVals = new byte[3][];
byte[] blueVals = new byte[bufferSize];
for (int j = 1; j >= 0; j--)
{
byte colour0 = blockStorage[j * 8]; // First 2 bytes are the min and max vals to be interpolated between
byte colour1 = blockStorage[1 + (j * 8)];
ulong longRep = BitConverter.ToUInt64(blockStorage, j * 8);
byte[] colVals = new byte[bufferSize];
//for (int k = 0; k < bufferSize; k++)
for (int k = bufferSize - 1; k >= 0; k--)
{
ulong tempLong = longRep | (ulong)ATI2BitCodes.interpColor5; // Set all trailing bits to 1
if ((tempLong ^ (ulong)ATI2BitCodes.color0) == (ulong)ATI2BitCodes.result) // First 2 values mean to use the specified min or max values
{
colVals[k] = colour0;
}
else if ((tempLong ^ (ulong)ATI2BitCodes.color1) == (ulong)ATI2BitCodes.result)
{
colVals[k] = colour1;
}
else if ((tempLong ^ (ulong)ATI2BitCodes.interpColor0) == (ulong)ATI2BitCodes.result) // Remaining values interpolate the min/max
{
if (colour0 > colour1)
colVals[k] = (byte)((6 * colour0 + colour1) / 7);
else
colVals[k] = (byte)((4 * colour0 + colour1) / 5);
}
else if ((tempLong ^ (ulong)ATI2BitCodes.interpColor1) == (ulong)ATI2BitCodes.result)
{
if (colour0 > colour1)
colVals[k] = (byte)((5 * colour0 + 2 * colour1) / 7);
else
colVals[k] = (byte)((3 * colour0 + 2 * colour1) / 5);
}
else if ((tempLong ^ (ulong)ATI2BitCodes.interpColor2) == (ulong)ATI2BitCodes.result)
{
if (colour0 > colour1)
colVals[k] = (byte)((4 * colour0 + 3 * colour1) / 7);
else
colVals[k] = (byte)((2 * colour0 + 3 * colour1) / 5);
}
else if ((tempLong ^ (ulong)ATI2BitCodes.interpColor3) == (ulong)ATI2BitCodes.result)
{
if (colour0 > colour1)
colVals[k] = (byte)((3 * colour0 + 4 * colour1) / 7);
else
colVals[k] = (byte)((colour0 + 4 * colour1) / 5);
}
else if ((tempLong ^ (ulong)ATI2BitCodes.interpColor4) == (ulong)ATI2BitCodes.result)
{
if (colour0 > colour1)
colVals[k] = (byte)((2 * colour0 + 5 * colour1) / 7);
else
colVals[k] = 0;
}
else if ((tempLong ^ (ulong)ATI2BitCodes.interpColor5) == (ulong)ATI2BitCodes.result)
{
if (colour0 > colour1)
colVals[k] = (byte)((colour0 + 6 * colour1) / 7);
else
colVals[k] = 255;
}
else
{
//MessageBox.Show("Error. Bitwise value not found."); // Safety catch. Shouldn't ever be encountered
throw new FormatException("Unknown bit value found. This shouldn't be possible...");
}
longRep <<= 3;
}
int index = (j == 0) ? 0 : 1;
rgbVals[index] = colVals;
}
for (int j = 0; j < bufferSize; j++)
{
if (rgbVals[0][j] <= 20 && rgbVals[1][j] <= 20)
blueVals[j] = 128;
else
blueVals[j] = 255;
}
rgbVals[2] = blueVals;
#endregion
for (int i = 0; i < 4; i++)
{
bitmapStream.Seek(((s + i) * w * bytesPerPixel) + (t * bytesPerPixel), SeekOrigin.Begin);
for (int j = 0; j < 4; j++)
{
//for (int k = 0; k < 3; k++)
for (int k = 2; k >= 0; k--)
bitmapStream.WriteByte(rgbVals[k][(i * 4) + j]);
}
}
}
}
byte[] imageData = bitmapStream.ToArray();
if (imageData.Length != (w * h * bytesPerPixel))
throw new FormatException("Incorect length of generated data array");
var bmp = new Bitmap(w, h, PixelFormat.Format24bppRgb);
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
Marshal.Copy(imageData, 0, bmpData.Scan0, imageData.Length);
bmp.UnlockBits(bmpData);
return bmp;
}
#endregion