private static LDRColorA Unquantize(LDRColorA c, LDRColorA RGBAPrec) { LDRColorA q = new LDRColorA(); q.r = Unquantize(c.r, RGBAPrec.r); q.g = Unquantize(c.g, RGBAPrec.g); q.b = Unquantize(c.b, RGBAPrec.b); q.a = RGBAPrec.a > 0 ? Unquantize(c.a, RGBAPrec.a) : (byte)255u; return(q); }
public ModeInfo(byte uParts, byte uPartBits, byte upBits, byte uRotBits, byte uIndModeBits, byte uIndPrec, byte uIndPrec2, LDRColorA rgbaPrec, LDRColorA rgbaPrecWithP) { uPartitions = uParts; uPartitionBits = uPartBits; uPBits = upBits; uRotationBits = uRotBits; uIndexModeBits = uIndModeBits; uIndexPrec = uIndPrec; uIndexPrec2 = uIndPrec2; RGBAPrec = rgbaPrec; RGBAPrecWithP = rgbaPrecWithP; }
protected override int Decode(byte[] stream, byte[] data, int streamIndex, uint dataIndex, uint stride) { // I would prefer to use Span, but not sure if I should reference System.Memory in this project // copy data instead Buffer.BlockCopy(stream, streamIndex, currentBlock, 0, currentBlock.Length); streamIndex += currentBlock.Length; uint uFirst = 0; while (uFirst < 128 && GetBit(ref uFirst) == 0) { } byte uMode = (byte)(uFirst - 1); if (uMode < 8) { byte uPartitions = ms_aInfo[uMode].uPartitions; Debug.Assert(uPartitions < Constants.BC7_MAX_REGIONS); var uNumEndPts = (byte)((uPartitions + 1u) << 1); byte uIndexPrec = ms_aInfo[uMode].uIndexPrec; byte uIndexPrec2 = ms_aInfo[uMode].uIndexPrec2; int i; uint uStartBit = uMode + 1u; int[] P = new int[6]; byte uShape = GetBits(ref uStartBit, ms_aInfo[uMode].uPartitionBits); Debug.Assert(uShape < Constants.BC7_MAX_SHAPES); byte uRotation = GetBits(ref uStartBit, ms_aInfo[uMode].uRotationBits); Debug.Assert(uRotation < 4); byte uIndexMode = GetBits(ref uStartBit, ms_aInfo[uMode].uIndexModeBits); Debug.Assert(uIndexMode < 2); LDRColorA[] c = new LDRColorA[Constants.BC7_MAX_REGIONS << 1]; for (i = 0; i < c.Length; ++i) { c[i] = new LDRColorA(); } LDRColorA RGBAPrec = ms_aInfo[uMode].RGBAPrec; LDRColorA RGBAPrecWithP = ms_aInfo[uMode].RGBAPrecWithP; Debug.Assert(uNumEndPts <= (Constants.BC7_MAX_REGIONS << 1)); // Red channel for (i = 0; i < uNumEndPts; i++) { if (uStartBit + RGBAPrec.r > 128) { Debug.WriteLine("BC7: Invalid block encountered during decoding"); Helpers.FillWithErrorColors(data, ref dataIndex, Constants.NUM_PIXELS_PER_BLOCK, DivSize, stride); return(streamIndex); } c[i].r = GetBits(ref uStartBit, RGBAPrec.r); } // Green channel for (i = 0; i < uNumEndPts; i++) { if (uStartBit + RGBAPrec.g > 128) { Debug.WriteLine("BC7: Invalid block encountered during decoding"); Helpers.FillWithErrorColors(data, ref dataIndex, Constants.NUM_PIXELS_PER_BLOCK, DivSize, stride); return(streamIndex); } c[i].g = GetBits(ref uStartBit, RGBAPrec.g); } // Blue channel for (i = 0; i < uNumEndPts; i++) { if (uStartBit + RGBAPrec.b > 128) { Debug.WriteLine("BC7: Invalid block encountered during decoding"); Helpers.FillWithErrorColors(data, ref dataIndex, Constants.NUM_PIXELS_PER_BLOCK, DivSize, stride); return(streamIndex); } c[i].b = GetBits(ref uStartBit, RGBAPrec.b); } // Alpha channel for (i = 0; i < uNumEndPts; i++) { if (uStartBit + RGBAPrec.a > 128) { Debug.WriteLine("BC7: Invalid block encountered during decoding"); Helpers.FillWithErrorColors(data, ref dataIndex, Constants.NUM_PIXELS_PER_BLOCK, DivSize, stride); return(streamIndex); } c[i].a = (byte)(RGBAPrec.a != 0 ? GetBits(ref uStartBit, RGBAPrec.a) : 255u); } // P-bits Debug.Assert(ms_aInfo[uMode].uPBits <= 6); for (i = 0; i < ms_aInfo[uMode].uPBits; i++) { if (uStartBit > 127) { Debug.WriteLine("BC7: Invalid block encountered during decoding"); Helpers.FillWithErrorColors(data, ref dataIndex, Constants.NUM_PIXELS_PER_BLOCK, DivSize, stride); return(streamIndex); } P[i] = GetBit(ref uStartBit); } if (ms_aInfo[uMode].uPBits != 0) { for (i = 0; i < uNumEndPts; i++) { int pi = i * ms_aInfo[uMode].uPBits / uNumEndPts; for (byte ch = 0; ch < Constants.BC7_NUM_CHANNELS; ch++) { if (RGBAPrec[ch] != RGBAPrecWithP[ch]) { c[i][ch] = (byte)((c[i][ch] << 1) | P[pi]); } } } } for (i = 0; i < uNumEndPts; i++) { c[i] = Unquantize(c[i], RGBAPrecWithP); } byte[] w1 = new byte[Constants.NUM_PIXELS_PER_BLOCK], w2 = new byte[Constants.NUM_PIXELS_PER_BLOCK]; // read color indices for (i = 0; i < Constants.NUM_PIXELS_PER_BLOCK; i++) { uint uNumBits = Helpers.IsFixUpOffset(ms_aInfo[uMode].uPartitions, uShape, i) ? uIndexPrec - 1u : uIndexPrec; if (uStartBit + uNumBits > 128) { Debug.WriteLine("BC7: Invalid block encountered during decoding"); Helpers.FillWithErrorColors(data, ref dataIndex, Constants.NUM_PIXELS_PER_BLOCK, DivSize, stride); return(streamIndex); } w1[i] = GetBits(ref uStartBit, uNumBits); } // read alpha indices if (uIndexPrec2 != 0) { for (i = 0; i < Constants.NUM_PIXELS_PER_BLOCK; i++) { uint uNumBits = (i != 0 ? uIndexPrec2 : uIndexPrec2 - 1u); if (uStartBit + uNumBits > 128) { Debug.WriteLine("BC7: Invalid block encountered during decoding"); Helpers.FillWithErrorColors(data, ref dataIndex, Constants.NUM_PIXELS_PER_BLOCK, DivSize, stride); return(streamIndex); } w2[i] = GetBits(ref uStartBit, uNumBits); } } for (i = 0; i < Constants.NUM_PIXELS_PER_BLOCK; ++i) { byte uRegion = Constants.g_aPartitionTable[uPartitions][uShape][i]; LDRColorA outPixel = new LDRColorA(); if (uIndexPrec2 == 0) { LDRColorA.Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w1[i], w1[i], uIndexPrec, uIndexPrec, outPixel); } else { if (uIndexMode == 0) { LDRColorA.Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w1[i], w2[i], uIndexPrec, uIndexPrec2, outPixel); } else { LDRColorA.Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w2[i], w1[i], uIndexPrec2, uIndexPrec, outPixel); } } switch (uRotation) { case 1: ByteSwap(ref outPixel.r, ref outPixel.a); break; case 2: ByteSwap(ref outPixel.g, ref outPixel.a); break; case 3: ByteSwap(ref outPixel.b, ref outPixel.a); break; } // Note: whether it's sRGB is not taken into consideration // we're returning data that could be either/or depending // on the input BC7 format data[dataIndex++] = outPixel.b; data[dataIndex++] = outPixel.g; data[dataIndex++] = outPixel.r; data[dataIndex++] = outPixel.a; // Is mult 4? if (((i + 1) & 0x3) == 0) { dataIndex += PixelDepthBytes * (stride - DivSize); } } } else { Debug.WriteLine("BC7: Reserved mode 8 encountered during decoding"); // Per the BC7 format spec, we must return transparent black for (int i = 0; i < Constants.NUM_PIXELS_PER_BLOCK; ++i) { data[dataIndex++] = 0; data[dataIndex++] = 0; data[dataIndex++] = 0; data[dataIndex++] = 0; // Is mult 4? if (((i + 1) & 0x3) == 0) { dataIndex += PixelDepthBytes * (stride - DivSize); } } } return(streamIndex); }