private static MipMap ReadCompressedMipMap(MemoryStream compressed, int mipWidth, int mipHeight, int blockSize, int mipOffset, bool isPremultiplied, Action<byte[], int, byte[], int, int, bool> DecompressBlock)
{
// Gets stream as data. Note that this array isn't necessarily the correct size. Likely to have garbage at the end.
// Don't want to use ToArray as that creates a new array. Don't want that.
byte[] CompressedData = compressed.GetBuffer();
byte[] decompressedData = new byte[4 * mipWidth * mipHeight];
int decompressedRowLength = mipWidth * 4;
int texelRowSkip = decompressedRowLength * 4;
int texelCount = (mipWidth * mipHeight) / 16;
int numTexelsInRow = mipWidth / 4;
if (texelCount != 0)
{
Action<int, ParallelLoopState> action = new Action<int, ParallelLoopState>((texelIndex, loopstate) =>
{
int compressedPosition = mipOffset + texelIndex * blockSize;
int decompressedStart = (int)(texelIndex / numTexelsInRow) * texelRowSkip + (texelIndex % numTexelsInRow) * 16;
// Problem with how I handle dimensions (no virtual padding or anything yet)
if (!UsefulThings.General.IsPowerOfTwo(mipWidth) || !UsefulThings.General.IsPowerOfTwo(mipHeight))
return;
try
{
DecompressBlock(CompressedData, compressedPosition, decompressedData, decompressedStart, decompressedRowLength, isPremultiplied);
}
catch (IndexOutOfRangeException e)
{
throw;
}
});
// Actually perform decompression using threading, no threading, or GPU.
if (ImageEngine.EnableGPUAcceleration)
Debugger.Break();
else if (ImageEngine.EnableThreading)
Parallel.For(0, texelCount, new ParallelOptions { MaxDegreeOfParallelism = ImageEngine.NumThreads }, (texelIndex, loopstate) => action(texelIndex, loopstate));
else
for (int texelIndex = 0; texelIndex < texelCount; texelIndex++)
action(texelIndex, null);
}
// No else here cos the lack of texels means it's below texel dimensions (4x4). So the resulting block is set to 0. Not ideal, but who sees 2x2 mipmaps?
return new MipMap(decompressedData, mipWidth, mipHeight);
}