Esempio n. 1
0
 public IntColor SignExtend(LdrColorA prec)
 {
     this.R = SIGN_EXTEND(this.R, prec.R);
     this.G = SIGN_EXTEND(this.G, prec.G);
     this.B = SIGN_EXTEND(this.B, prec.B);
     return(this);
 }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
 public Bc7ModeInfo(byte uParts, byte uPartBits, byte upBits, byte uRotBits, byte uIndModeBits, byte uIndPrec, byte uIndPrec2, LdrColorA rgbaPrec, LdrColorA rgbaPrecWithP)
 {
     this.UPartitions    = uParts;
     this.UPartitionBits = uPartBits;
     this.UPBits         = upBits;
     this.URotationBits  = uRotBits;
     this.UIndexModeBits = uIndModeBits;
     this.UIndexPrec     = uIndPrec;
     this.UIndexPrec2    = uIndPrec2;
     this.RgbaPrec       = rgbaPrec;
     this.RgbaPrecWithP  = rgbaPrecWithP;
 }
Esempio n. 4
0
        private static LdrColorA Unquantize(LdrColorA c, LdrColorA rgbaPrec)
        {
            var q = new LdrColorA
            {
                R = Unquantize(c.R, rgbaPrec.R),
                G = Unquantize(c.G, rgbaPrec.G),
                B = Unquantize(c.B, rgbaPrec.B),
                A = rgbaPrec.A > 0 ? Unquantize(c.A, rgbaPrec.A) : (byte)255u
            };

            return(q);
        }
Esempio n. 5
0
 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;
 }
Esempio n. 6
0
        /// <inheritdoc/>
        public byte[] Decompress(byte[] blockData, int width, int height)
        {
            byte[] currentBlock = new byte[this.CompressedBytesPerBlock];
            IBlock self         = this;

            return(Helper.InMemoryDecode <Bc7>(blockData, width, height, (stream, data, streamIndex, dataIndex, stride) =>
            {
                // I would prefer to use Span, but not sure if I should reference System.Memory in this project copy data instead.
                Buffer.BlockCopy(blockData, streamIndex, currentBlock, 0, currentBlock.Length);
                streamIndex += currentBlock.Length;

                uint uFirst = 0;
                while (uFirst < 128 && GetBit(currentBlock, ref uFirst) == 0)
                {
                }

                byte uMode = (byte)(uFirst - 1);

                if (uMode < 8)
                {
                    byte uPartitions = ModeInfos[uMode].UPartitions;
                    Debug.Assert(uPartitions < Constants.BC7_MAX_REGIONS, $"uPartitions should be smaller then {Constants.BC7_MAX_REGIONS}");

                    byte uNumEndPts = (byte)((uPartitions + 1u) << 1);
                    byte uIndexPrec = ModeInfos[uMode].UIndexPrec;
                    byte uIndexPrec2 = ModeInfos[uMode].UIndexPrec2;
                    int i;
                    uint uStartBit = uMode + 1u;
                    int[] p = new int[6];
                    byte uShape = GetBits(currentBlock, ref uStartBit, ModeInfos[uMode].UPartitionBits);
                    Debug.Assert(uShape < Constants.BC7_MAX_SHAPES, $"uShape should be smaller then {Constants.BC7_MAX_SHAPES}");

                    byte uRotation = GetBits(currentBlock, ref uStartBit, ModeInfos[uMode].URotationBits);
                    Debug.Assert(uRotation < 4, "uRotation should be less then 4");

                    byte uIndexMode = GetBits(currentBlock, ref uStartBit, ModeInfos[uMode].UIndexModeBits);
                    Debug.Assert(uIndexMode < 2, "uIndexMode should be less then 2");

                    var c = new LdrColorA[Constants.BC7_MAX_REGIONS << 1];
                    for (i = 0; i < c.Length; ++i)
                    {
                        c[i] = new LdrColorA();
                    }

                    LdrColorA rgbaPrec = ModeInfos[uMode].RgbaPrec;
                    LdrColorA rgbaPrecWithP = ModeInfos[uMode].RgbaPrecWithP;

                    Debug.Assert(uNumEndPts <= (Constants.BC7_MAX_REGIONS << 1), $"uNumEndPts should be smaller or equal to {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.NumPixelsPerBlock, self.DivSize, stride);
                            return dataIndex;
                        }

                        c[i].R = GetBits(currentBlock, 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.NumPixelsPerBlock, self.DivSize, stride);
                            return dataIndex;
                        }

                        c[i].G = GetBits(currentBlock, 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.NumPixelsPerBlock, self.DivSize, stride);
                            return dataIndex;
                        }

                        c[i].B = GetBits(currentBlock, 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.NumPixelsPerBlock, self.DivSize, stride);
                            return dataIndex;
                        }

                        c[i].A = (byte)(rgbaPrec.A != 0 ? GetBits(currentBlock, ref uStartBit, rgbaPrec.A) : 255u);
                    }

                    // P-bits
                    Debug.Assert(ModeInfos[uMode].UPBits <= 6, "ModeInfos[uMode].UPBits should be less then 7");
                    for (i = 0; i < ModeInfos[uMode].UPBits; i++)
                    {
                        if (uStartBit > 127)
                        {
                            Debug.WriteLine("BC7: Invalid block encountered during decoding");
                            Helpers.FillWithErrorColors(data, ref dataIndex, Constants.NumPixelsPerBlock, self.DivSize, stride);
                            return dataIndex;
                        }

                        p[i] = GetBit(currentBlock, ref uStartBit);
                    }

                    if (ModeInfos[uMode].UPBits != 0)
                    {
                        for (i = 0; i < uNumEndPts; i++)
                        {
                            int pi = i * ModeInfos[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.NumPixelsPerBlock], w2 = new byte[Constants.NumPixelsPerBlock];

                    // read color indices
                    for (i = 0; i < Constants.NumPixelsPerBlock; i++)
                    {
                        uint uNumBits = Helpers.IsFixUpOffset(ModeInfos[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.NumPixelsPerBlock, self.DivSize, stride);
                            return dataIndex;
                        }

                        w1[i] = GetBits(currentBlock, ref uStartBit, uNumBits);
                    }

                    // read alpha indices
                    if (uIndexPrec2 != 0)
                    {
                        for (i = 0; i < Constants.NumPixelsPerBlock; 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.NumPixelsPerBlock, self.DivSize, stride);
                                return dataIndex;
                            }

                            w2[i] = GetBits(currentBlock, ref uStartBit, uNumBits);
                        }
                    }

                    for (i = 0; i < Constants.NumPixelsPerBlock; ++i)
                    {
                        byte uRegion = Constants.PartitionTable[uPartitions][uShape][i];
                        var 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: outPixel.SwapRedWithAlpha(); break;

                        case 2: outPixel.SwapGreenWithAlpha(); break;

                        case 3: outPixel.SwapBlueWithAlpha(); 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.R;
                        data[dataIndex++] = outPixel.G;
                        data[dataIndex++] = outPixel.B;
                        data[dataIndex++] = outPixel.A;

                        // Is mult 4?
                        if (((i + 1) & 0x3) == 0)
                        {
                            dataIndex += self.PixelDepthBytes * (stride - self.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.NumPixelsPerBlock; ++i)
                    {
                        data[dataIndex++] = 0;
                        data[dataIndex++] = 0;
                        data[dataIndex++] = 0;
                        data[dataIndex++] = 0;

                        // Is mult 4?
                        if (((i + 1) & 0x3) == 0)
                        {
                            dataIndex += self.PixelDepthBytes * (stride - self.DivSize);
                        }
                    }
                }

                return streamIndex;
            }));
        }
Esempio n. 7
0
        public byte[] Decompress(byte[] blockData, int width, int height)
        {
            var    currentBlock = new byte[CompressedBytesPerBlock];
            IBlock self         = this;

            return(Helper.InMemoryDecode <Bc7>(blockData, width, height, (byte[] stream, byte[] data, int streamIndex, int dataIndex, int stride) =>
            {
                // I would prefer to use Span, but not sure if I should reference System.Memory in this project
                // copy data instead
                Buffer.BlockCopy(blockData, (int)streamIndex, currentBlock, 0, currentBlock.Length);
                streamIndex += (int)currentBlock.Length;

                uint uFirst = 0;
                while (uFirst < 128 && GetBit(currentBlock, 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(currentBlock, ref uStartBit, ms_aInfo[uMode].uPartitionBits);
                    Debug.Assert(uShape < Constants.BC7_MAX_SHAPES);

                    byte uRotation = GetBits(currentBlock, ref uStartBit, ms_aInfo[uMode].uRotationBits);
                    Debug.Assert(uRotation < 4);

                    byte uIndexMode = GetBits(currentBlock, 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, self.DivSize, stride);
                            return dataIndex;
                        }

                        c[i].r = GetBits(currentBlock, 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, self.DivSize, stride);
                            return dataIndex;
                        }

                        c[i].g = GetBits(currentBlock, 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, self.DivSize, stride);
                            return dataIndex;
                        }

                        c[i].b = GetBits(currentBlock, 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, self.DivSize, stride);
                            return dataIndex;
                        }

                        c[i].a = (byte)(RGBAPrec.a != 0 ? GetBits(currentBlock, 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, self.DivSize, stride);
                            return dataIndex;
                        }

                        P[i] = GetBit(currentBlock, 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, self.DivSize, stride);
                            return dataIndex;
                        }
                        w1[i] = GetBits(currentBlock, 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, self.DivSize, stride);
                                return dataIndex;
                            }
                            w2[i] = GetBits(currentBlock, 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 += self.PixelDepthBytes * (stride - self.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 += self.PixelDepthBytes * (stride - self.DivSize);
                        }
                    }
                }
                return streamIndex;
            }));
        }