Beispiel #1
0
 private static void Unquantize(ref RgbaColor32 color, int colorDepth, int alphaDepth, int pBit)
 {
     color.R = UnquantizeComponent(color.R, colorDepth, pBit);
     color.G = UnquantizeComponent(color.G, colorDepth, pBit);
     color.B = UnquantizeComponent(color.B, colorDepth, pBit);
     color.A = alphaDepth != 0 ? UnquantizeComponent(color.A, alphaDepth, pBit) : 255;
 }
Beispiel #2
0
        private static unsafe int GetEndPointSelectionErrorFast(ReadOnlySpan <uint> tile, int subsetCount, int partition, int w, int h, int maxError)
        {
            byte[] partitionTable = BC67Tables.PartitionTable[subsetCount - 1][partition];

            Span <RgbaColor8> minColors = stackalloc RgbaColor8[subsetCount];
            Span <RgbaColor8> maxColors = stackalloc RgbaColor8[subsetCount];

            BC67Utils.GetMinMaxColors(partitionTable, tile, w, h, minColors, maxColors, subsetCount);

            Span <uint> endPoints0 = stackalloc uint[subsetCount];
            Span <uint> endPoints1 = stackalloc uint[subsetCount];

            SelectEndPointsFast(partitionTable, tile, w, h, subsetCount, minColors, maxColors, endPoints0, endPoints1, uint.MaxValue);

            Span <RgbaColor32> palette = stackalloc RgbaColor32[8];

            int errorSum = 0;

            for (int subset = 0; subset < subsetCount; subset++)
            {
                RgbaColor32 blockDir = maxColors[subset].GetColor32() - minColors[subset].GetColor32();
                int         sum      = blockDir.R + blockDir.G + blockDir.B + blockDir.A;
                if (sum != 0)
                {
                    blockDir = (blockDir << 6) / new RgbaColor32(sum);
                }

                uint c0 = endPoints0[subset];
                uint c1 = endPoints1[subset];

                int pBit0 = GetPBit(c0, 6, 0);
                int pBit1 = GetPBit(c1, 6, 0);

                c0 = BC67Utils.Quantize(RgbaColor8.FromUInt32(c0), 6, 0, pBit0).ToUInt32();
                c1 = BC67Utils.Quantize(RgbaColor8.FromUInt32(c1), 6, 0, pBit1).ToUInt32();

                if (Sse41.IsSupported)
                {
                    Vector128 <byte> c0Rep = Vector128.Create(c0).AsByte();
                    Vector128 <byte> c1Rep = Vector128.Create(c1).AsByte();

                    Vector128 <byte> c0c1 = Sse2.UnpackLow(c0Rep, c1Rep);

                    Vector128 <byte> rWeights;
                    Vector128 <byte> lWeights;

                    fixed(byte *pWeights = BC67Tables.Weights[1], pInvWeights = BC67Tables.InverseWeights[1])
                    {
                        rWeights = Sse2.LoadScalarVector128((ulong *)pWeights).AsByte();
                        lWeights = Sse2.LoadScalarVector128((ulong *)pInvWeights).AsByte();
                    }

                    Vector128 <byte> iWeights   = Sse2.UnpackLow(rWeights, lWeights);
                    Vector128 <byte> iWeights01 = Sse2.UnpackLow(iWeights.AsInt16(), iWeights.AsInt16()).AsByte();
                    Vector128 <byte> iWeights23 = Sse2.UnpackHigh(iWeights.AsInt16(), iWeights.AsInt16()).AsByte();
                    Vector128 <byte> iWeights0  = Sse2.UnpackLow(iWeights01.AsInt16(), iWeights01.AsInt16()).AsByte();
                    Vector128 <byte> iWeights1  = Sse2.UnpackHigh(iWeights01.AsInt16(), iWeights01.AsInt16()).AsByte();
                    Vector128 <byte> iWeights2  = Sse2.UnpackLow(iWeights23.AsInt16(), iWeights23.AsInt16()).AsByte();
                    Vector128 <byte> iWeights3  = Sse2.UnpackHigh(iWeights23.AsInt16(), iWeights23.AsInt16()).AsByte();
Beispiel #3
0
        private static void DecodeBlock(Block block, Span <uint> output, int w, int h, int width)
        {
            int mode = BitOperations.TrailingZeroCount((byte)block.Low | 0x100);

            if (mode == 8)
            {
                // Mode is invalid, the spec mandates that hardware fills the block with
                // a transparent black color.
                for (int ty = 0; ty < h; ty++)
                {
                    int baseOffs = ty * width;

                    for (int tx = 0; tx < w; tx++)
                    {
                        int offs = baseOffs + tx;

                        output[offs] = 0;
                    }
                }

                return;
            }

            BC7ModeInfo modeInfo = BC67Tables.BC7ModeInfos[mode];

            int offset    = mode + 1;
            int partition = (int)block.Decode(ref offset, modeInfo.PartitionBitCount);
            int rotation  = (int)block.Decode(ref offset, modeInfo.RotationBitCount);
            int indexMode = (int)block.Decode(ref offset, modeInfo.IndexModeBitCount);

            Debug.Assert(partition < 64);
            Debug.Assert(rotation < 4);
            Debug.Assert(indexMode < 2);

            int endPointCount = modeInfo.SubsetCount * 2;

            Span <RgbaColor32> endPoints = stackalloc RgbaColor32[endPointCount];
            Span <byte>        pValues   = stackalloc byte[modeInfo.PBits];

            endPoints.Fill(new RgbaColor32(0, 0, 0, 255));

            for (int i = 0; i < endPointCount; i++)
            {
                endPoints[i].R = (int)block.Decode(ref offset, modeInfo.ColorDepth);
            }

            for (int i = 0; i < endPointCount; i++)
            {
                endPoints[i].G = (int)block.Decode(ref offset, modeInfo.ColorDepth);
            }

            for (int i = 0; i < endPointCount; i++)
            {
                endPoints[i].B = (int)block.Decode(ref offset, modeInfo.ColorDepth);
            }

            if (modeInfo.AlphaDepth != 0)
            {
                for (int i = 0; i < endPointCount; i++)
                {
                    endPoints[i].A = (int)block.Decode(ref offset, modeInfo.AlphaDepth);
                }
            }

            for (int i = 0; i < modeInfo.PBits; i++)
            {
                pValues[i] = (byte)block.Decode(ref offset, 1);
            }

            for (int i = 0; i < endPointCount; i++)
            {
                int pBit = -1;

                if (modeInfo.PBits != 0)
                {
                    int pIndex = (i * modeInfo.PBits) / endPointCount;
                    pBit = pValues[pIndex];
                }

                Unquantize(ref endPoints[i], modeInfo.ColorDepth, modeInfo.AlphaDepth, pBit);
            }

            byte[] partitionTable = BC67Tables.PartitionTable[modeInfo.SubsetCount - 1][partition];
            byte[] fixUpTable     = BC67Tables.FixUpIndices[modeInfo.SubsetCount - 1][partition];

            Span <byte> colorIndices = stackalloc byte[16];

            for (int i = 0; i < 16; i++)
            {
                byte subset   = partitionTable[i];
                int  bitCount = i == fixUpTable[subset] ? modeInfo.ColorIndexBitCount - 1 : modeInfo.ColorIndexBitCount;

                colorIndices[i] = (byte)block.Decode(ref offset, bitCount);
                Debug.Assert(colorIndices[i] < 16);
            }

            Span <byte> alphaIndices = stackalloc byte[16];

            if (modeInfo.AlphaIndexBitCount != 0)
            {
                for (int i = 0; i < 16; i++)
                {
                    int bitCount = i != 0 ? modeInfo.AlphaIndexBitCount : modeInfo.AlphaIndexBitCount - 1;

                    alphaIndices[i] = (byte)block.Decode(ref offset, bitCount);
                    Debug.Assert(alphaIndices[i] < 16);
                }
            }

            for (int ty = 0; ty < h; ty++)
            {
                int baseOffs = ty * width;

                for (int tx = 0; tx < w; tx++)
                {
                    int i = ty * 4 + tx;

                    RgbaColor32 color;

                    byte subset = partitionTable[i];

                    RgbaColor32 color1 = endPoints[subset * 2];
                    RgbaColor32 color2 = endPoints[subset * 2 + 1];

                    if (modeInfo.AlphaIndexBitCount != 0)
                    {
                        if (indexMode == 0)
                        {
                            color = BC67Utils.Interpolate(color1, color2, colorIndices[i], alphaIndices[i], modeInfo.ColorIndexBitCount, modeInfo.AlphaIndexBitCount);
                        }
                        else
                        {
                            color = BC67Utils.Interpolate(color1, color2, alphaIndices[i], colorIndices[i], modeInfo.AlphaIndexBitCount, modeInfo.ColorIndexBitCount);
                        }
                    }
                    else
                    {
                        color = BC67Utils.Interpolate(color1, color2, colorIndices[i], colorIndices[i], modeInfo.ColorIndexBitCount, modeInfo.ColorIndexBitCount);
                    }

                    if (rotation != 0)
                    {
                        int a = color.A;

                        switch (rotation)
                        {
                        case 1: color.A = color.R; color.R = a; break;

                        case 2: color.A = color.G; color.G = a; break;

                        case 3: color.A = color.B; color.B = a; break;
                        }
                    }

                    RgbaColor8 color8 = color.GetColor8();

                    output[baseOffs + tx] = color8.ToUInt32();
                }
            }
        }
Beispiel #4
0
        private static void DecodeBlock(Block block, Span <ulong> output, int w, int h, int width, bool signed)
        {
            int mode = (int)(block.Low & 3);

            if ((mode & 2) != 0)
            {
                mode = (int)(block.Low & 0x1f);
            }

            Span <RgbaColor32> endPoints = stackalloc RgbaColor32[4];
            int subsetCount = DecodeEndPoints(ref block, endPoints, mode, signed);

            if (subsetCount == 0)
            {
                // Mode is invalid, the spec mandates that hardware fills the block with
                // a opaque black color.
                for (int ty = 0; ty < h; ty++)
                {
                    int baseOffs = ty * width;

                    for (int tx = 0; tx < w; tx++)
                    {
                        output[baseOffs + tx] = (ulong)HalfOne << 48;
                    }
                }

                return;
            }

            int   partition;
            int   indexBitCount;
            ulong indices;

            if (subsetCount > 1)
            {
                partition     = (int)((block.High >> 13) & 0x1F);
                indexBitCount = 3;

                int   fixUpIndex = BC67Tables.FixUpIndices[subsetCount - 1][partition][1] * 3;
                ulong lowMask    = (ulong.MaxValue >> (65 - fixUpIndex)) << 3;
                ulong highMask   = ulong.MaxValue << (fixUpIndex + 3);

                indices = ((block.High >> 16) & highMask) | ((block.High >> 17) & lowMask) | ((block.High >> 18) & 3);
            }
            else
            {
                partition     = 0;
                indexBitCount = 4;
                indices       = (block.High & ~0xFUL) | ((block.High >> 1) & 7);
            }

            ulong indexMask = (1UL << indexBitCount) - 1;

            for (int ty = 0; ty < h; ty++)
            {
                int baseOffs = ty * width;

                for (int tx = 0; tx < w; tx++)
                {
                    int offs         = baseOffs + tx;
                    int index        = (int)(indices & indexMask);
                    int endPointBase = BC67Tables.PartitionTable[subsetCount - 1][partition][ty * 4 + tx] << 1;

                    RgbaColor32 color1 = endPoints[endPointBase];
                    RgbaColor32 color2 = endPoints[endPointBase + 1];

                    RgbaColor32 color = BC67Utils.Interpolate(color1, color2, index, indexBitCount);

                    output[offs] =
                        (ulong)FinishUnquantize(color.R, signed) |
                        ((ulong)FinishUnquantize(color.G, signed) << 16) |
                        ((ulong)FinishUnquantize(color.B, signed) << 32) |
                        ((ulong)HalfOne << 48);

                    indices >>= indexBitCount;
                }
            }
        }
Beispiel #5
0
        private static int DecodeEndPoints(ref Block block, Span <RgbaColor32> endPoints, int mode, bool signed)
        {
            ulong low  = block.Low;
            ulong high = block.High;

            int r0 = 0, g0 = 0, b0 = 0, r1 = 0, g1 = 0, b1 = 0, r2 = 0, g2 = 0, b2 = 0, r3 = 0, g3 = 0, b3 = 0;
            int subsetCount;

            switch (mode)
            {
            case 0:
                r0 = (int)(low >> 5) & 0x3FF;
                g0 = (int)(low >> 15) & 0x3FF;
                b0 = (int)(low >> 25) & 0x3FF;

                if (signed)
                {
                    r0 = SignExtend(r0, 10);
                    g0 = SignExtend(g0, 10);
                    b0 = SignExtend(b0, 10);
                }

                r1 = r0 + SignExtend((int)(low >> 35), 5);
                g1 = g0 + SignExtend((int)(low >> 45), 5);
                b1 = b0 + SignExtend((int)(low >> 55), 5);

                r2 = r0 + SignExtend((int)(high >> 1), 5);
                g2 = g0 + SignExtend((int)(((low << 2) & 0x10) | ((low >> 41) & 0xF)), 5);
                b2 = b0 + SignExtend((int)(((low << 1) & 0x10) | ((high << 3) & 0x08) | (low >> 61)), 5);

                r3 = r0 + SignExtend((int)(high >> 7), 5);
                g3 = g0 + SignExtend((int)(((low >> 36) & 0x10) | ((low >> 51) & 0xF)), 5);
                b3 = b0 + SignExtend((int)(
                                         ((low) & 0x10) |
                                         ((high >> 9) & 0x08) |
                                         ((high >> 4) & 0x04) |
                                         ((low >> 59) & 0x02) |
                                         ((low >> 50) & 0x01)), 5);

                r0 = Unquantize(r0, 10, signed);
                g0 = Unquantize(g0, 10, signed);
                b0 = Unquantize(b0, 10, signed);

                r1 = Unquantize(r1 & 0x3FF, 10, signed);
                g1 = Unquantize(g1 & 0x3FF, 10, signed);
                b1 = Unquantize(b1 & 0x3FF, 10, signed);

                r2 = Unquantize(r2 & 0x3FF, 10, signed);
                g2 = Unquantize(g2 & 0x3FF, 10, signed);
                b2 = Unquantize(b2 & 0x3FF, 10, signed);

                r3 = Unquantize(r3 & 0x3FF, 10, signed);
                g3 = Unquantize(g3 & 0x3FF, 10, signed);
                b3 = Unquantize(b3 & 0x3FF, 10, signed);

                subsetCount = 2;
                break;

            case 1:
                r0 = (int)(low >> 5) & 0x7F;
                g0 = (int)(low >> 15) & 0x7F;
                b0 = (int)(low >> 25) & 0x7F;

                if (signed)
                {
                    r0 = SignExtend(r0, 7);
                    g0 = SignExtend(g0, 7);
                    b0 = SignExtend(b0, 7);
                }

                r1 = r0 + SignExtend((int)(low >> 35), 6);
                g1 = g0 + SignExtend((int)(low >> 45), 6);
                b1 = b0 + SignExtend((int)(low >> 55), 6);

                r2 = r0 + SignExtend((int)(high >> 1), 6);
                g2 = g0 + SignExtend((int)(((low << 3) & 0x20) | ((low >> 20) & 0x10) | ((low >> 41) & 0x0F)), 6);
                b2 = b0 + SignExtend((int)(
                                         ((low >> 17) & 0x20) |
                                         ((low >> 10) & 0x10) |
                                         ((high << 3) & 0x08) |
                                         (low >> 61)), 6);

                r3 = r0 + SignExtend((int)(high >> 7), 6);
                g3 = g0 + SignExtend((int)(((low << 1) & 0x30) | ((low >> 51) & 0xF)), 6);
                b3 = b0 + SignExtend((int)(
                                         ((low >> 28) & 0x20) |
                                         ((low >> 30) & 0x10) |
                                         ((low >> 29) & 0x08) |
                                         ((low >> 21) & 0x04) |
                                         ((low >> 12) & 0x03)), 6);

                r0 = Unquantize(r0, 7, signed);
                g0 = Unquantize(g0, 7, signed);
                b0 = Unquantize(b0, 7, signed);

                r1 = Unquantize(r1 & 0x7F, 7, signed);
                g1 = Unquantize(g1 & 0x7F, 7, signed);
                b1 = Unquantize(b1 & 0x7F, 7, signed);

                r2 = Unquantize(r2 & 0x7F, 7, signed);
                g2 = Unquantize(g2 & 0x7F, 7, signed);
                b2 = Unquantize(b2 & 0x7F, 7, signed);

                r3 = Unquantize(r3 & 0x7F, 7, signed);
                g3 = Unquantize(g3 & 0x7F, 7, signed);
                b3 = Unquantize(b3 & 0x7F, 7, signed);

                subsetCount = 2;
                break;

            case 2:
                r0 = (int)(((low >> 30) & 0x400) | ((low >> 5) & 0x3FF));
                g0 = (int)(((low >> 39) & 0x400) | ((low >> 15) & 0x3FF));
                b0 = (int)(((low >> 49) & 0x400) | ((low >> 25) & 0x3FF));

                if (signed)
                {
                    r0 = SignExtend(r0, 11);
                    g0 = SignExtend(g0, 11);
                    b0 = SignExtend(b0, 11);
                }

                r1 = r0 + SignExtend((int)(low >> 35), 5);
                g1 = g0 + SignExtend((int)(low >> 45), 4);
                b1 = b0 + SignExtend((int)(low >> 55), 4);

                r2 = r0 + SignExtend((int)(high >> 1), 5);
                g2 = g0 + SignExtend((int)(low >> 41), 4);
                b2 = b0 + SignExtend((int)(((high << 3) & 8) | (low >> 61)), 4);

                r3 = r0 + SignExtend((int)(high >> 7), 5);
                g3 = g0 + SignExtend((int)(low >> 51), 4);
                b3 = b0 + SignExtend((int)(
                                         ((high >> 9) & 8) |
                                         ((high >> 4) & 4) |
                                         ((low >> 59) & 2) |
                                         ((low >> 50) & 1)), 4);

                r0 = Unquantize(r0, 11, signed);
                g0 = Unquantize(g0, 11, signed);
                b0 = Unquantize(b0, 11, signed);

                r1 = Unquantize(r1 & 0x7FF, 11, signed);
                g1 = Unquantize(g1 & 0x7FF, 11, signed);
                b1 = Unquantize(b1 & 0x7FF, 11, signed);

                r2 = Unquantize(r2 & 0x7FF, 11, signed);
                g2 = Unquantize(g2 & 0x7FF, 11, signed);
                b2 = Unquantize(b2 & 0x7FF, 11, signed);

                r3 = Unquantize(r3 & 0x7FF, 11, signed);
                g3 = Unquantize(g3 & 0x7FF, 11, signed);
                b3 = Unquantize(b3 & 0x7FF, 11, signed);

                subsetCount = 2;
                break;

            case 3:
                r0 = (int)(low >> 5) & 0x3FF;
                g0 = (int)(low >> 15) & 0x3FF;
                b0 = (int)(low >> 25) & 0x3FF;

                r1 = (int)(low >> 35) & 0x3FF;
                g1 = (int)(low >> 45) & 0x3FF;
                b1 = (int)(((high << 9) & 0x200) | (low >> 55));

                if (signed)
                {
                    r0 = SignExtend(r0, 10);
                    g0 = SignExtend(g0, 10);
                    b0 = SignExtend(b0, 10);

                    r1 = SignExtend(r1, 10);
                    g1 = SignExtend(g1, 10);
                    b1 = SignExtend(b1, 10);
                }

                r0 = Unquantize(r0, 10, signed);
                g0 = Unquantize(g0, 10, signed);
                b0 = Unquantize(b0, 10, signed);

                r1 = Unquantize(r1, 10, signed);
                g1 = Unquantize(g1, 10, signed);
                b1 = Unquantize(b1, 10, signed);

                subsetCount = 1;
                break;

            case 6:
                r0 = (int)(((low >> 29) & 0x400) | ((low >> 5) & 0x3FF));
                g0 = (int)(((low >> 40) & 0x400) | ((low >> 15) & 0x3FF));
                b0 = (int)(((low >> 49) & 0x400) | ((low >> 25) & 0x3FF));

                if (signed)
                {
                    r0 = SignExtend(r0, 11);
                    g0 = SignExtend(g0, 11);
                    b0 = SignExtend(b0, 11);
                }

                r1 = r0 + SignExtend((int)(low >> 35), 4);
                g1 = g0 + SignExtend((int)(low >> 45), 5);
                b1 = b0 + SignExtend((int)(low >> 55), 4);

                r2 = r0 + SignExtend((int)(high >> 1), 4);
                g2 = g0 + SignExtend((int)(((high >> 7) & 0x10) | ((low >> 41) & 0x0F)), 5);
                b2 = b0 + SignExtend((int)(((high << 3) & 0x08) | ((low >> 61))), 4);

                r3 = r0 + SignExtend((int)(high >> 7), 4);
                g3 = g0 + SignExtend((int)(((low >> 36) & 0x10) | ((low >> 51) & 0x0F)), 5);
                b3 = b0 + SignExtend((int)(
                                         ((high >> 9) & 8) |
                                         ((high >> 4) & 4) |
                                         ((low >> 59) & 2) |
                                         ((high >> 5) & 1)), 4);

                r0 = Unquantize(r0, 11, signed);
                g0 = Unquantize(g0, 11, signed);
                b0 = Unquantize(b0, 11, signed);

                r1 = Unquantize(r1 & 0x7FF, 11, signed);
                g1 = Unquantize(g1 & 0x7FF, 11, signed);
                b1 = Unquantize(b1 & 0x7FF, 11, signed);

                r2 = Unquantize(r2 & 0x7FF, 11, signed);
                g2 = Unquantize(g2 & 0x7FF, 11, signed);
                b2 = Unquantize(b2 & 0x7FF, 11, signed);

                r3 = Unquantize(r3 & 0x7FF, 11, signed);
                g3 = Unquantize(g3 & 0x7FF, 11, signed);
                b3 = Unquantize(b3 & 0x7FF, 11, signed);

                subsetCount = 2;
                break;

            case 7:
                r0 = (int)(((low >> 34) & 0x400) | ((low >> 5) & 0x3FF));
                g0 = (int)(((low >> 44) & 0x400) | ((low >> 15) & 0x3FF));
                b0 = (int)(((high << 10) & 0x400) | ((low >> 25) & 0x3FF));

                if (signed)
                {
                    r0 = SignExtend(r0, 11);
                    g0 = SignExtend(g0, 11);
                    b0 = SignExtend(b0, 11);
                }

                r1 = (r0 + SignExtend((int)(low >> 35), 9)) & 0x7FF;
                g1 = (g0 + SignExtend((int)(low >> 45), 9)) & 0x7FF;
                b1 = (b0 + SignExtend((int)(low >> 55), 9)) & 0x7FF;

                r0 = Unquantize(r0, 11, signed);
                g0 = Unquantize(g0, 11, signed);
                b0 = Unquantize(b0, 11, signed);

                r1 = Unquantize(r1, 11, signed);
                g1 = Unquantize(g1, 11, signed);
                b1 = Unquantize(b1, 11, signed);

                subsetCount = 1;
                break;

            case 10:
                r0 = (int)(((low >> 29) & 0x400) | ((low >> 5) & 0x3FF));
                g0 = (int)(((low >> 39) & 0x400) | ((low >> 15) & 0x3FF));
                b0 = (int)(((low >> 50) & 0x400) | ((low >> 25) & 0x3FF));

                if (signed)
                {
                    r0 = SignExtend(r0, 11);
                    g0 = SignExtend(g0, 11);
                    b0 = SignExtend(b0, 11);
                }

                r1 = r0 + SignExtend((int)(low >> 35), 4);
                g1 = g0 + SignExtend((int)(low >> 45), 4);
                b1 = b0 + SignExtend((int)(low >> 55), 5);

                r2 = r0 + SignExtend((int)(high >> 1), 4);
                g2 = g0 + SignExtend((int)(low >> 41), 4);
                b2 = b0 + SignExtend((int)(((low >> 36) & 0x10) | ((high << 3) & 8) | (low >> 61)), 5);

                r3 = r0 + SignExtend((int)(high >> 7), 4);
                g3 = g0 + SignExtend((int)(low >> 51), 4);
                b3 = b0 + SignExtend((int)(
                                         ((high >> 7) & 0x10) |
                                         ((high >> 9) & 0x08) |
                                         ((high >> 4) & 0x06) |
                                         ((low >> 50) & 0x01)), 5);

                r0 = Unquantize(r0, 11, signed);
                g0 = Unquantize(g0, 11, signed);
                b0 = Unquantize(b0, 11, signed);

                r1 = Unquantize(r1 & 0x7FF, 11, signed);
                g1 = Unquantize(g1 & 0x7FF, 11, signed);
                b1 = Unquantize(b1 & 0x7FF, 11, signed);

                r2 = Unquantize(r2 & 0x7FF, 11, signed);
                g2 = Unquantize(g2 & 0x7FF, 11, signed);
                b2 = Unquantize(b2 & 0x7FF, 11, signed);

                r3 = Unquantize(r3 & 0x7FF, 11, signed);
                g3 = Unquantize(g3 & 0x7FF, 11, signed);
                b3 = Unquantize(b3 & 0x7FF, 11, signed);

                subsetCount = 2;
                break;

            case 11:
                r0 = (int)(((low >> 32) & 0x800) | ((low >> 34) & 0x400) | ((low >> 5) & 0x3FF));
                g0 = (int)(((low >> 42) & 0x800) | ((low >> 44) & 0x400) | ((low >> 15) & 0x3FF));
                b0 = (int)(((low >> 52) & 0x800) | ((high << 10) & 0x400) | ((low >> 25) & 0x3FF));

                if (signed)
                {
                    r0 = SignExtend(r0, 12);
                    g0 = SignExtend(g0, 12);
                    b0 = SignExtend(b0, 12);
                }

                r1 = (r0 + SignExtend((int)(low >> 35), 8)) & 0xFFF;
                g1 = (g0 + SignExtend((int)(low >> 45), 8)) & 0xFFF;
                b1 = (b0 + SignExtend((int)(low >> 55), 8)) & 0xFFF;

                r0 = Unquantize(r0, 12, signed);
                g0 = Unquantize(g0, 12, signed);
                b0 = Unquantize(b0, 12, signed);

                r1 = Unquantize(r1, 12, signed);
                g1 = Unquantize(g1, 12, signed);
                b1 = Unquantize(b1, 12, signed);

                subsetCount = 1;
                break;

            case 14:
                r0 = (int)(low >> 5) & 0x1FF;
                g0 = (int)(low >> 15) & 0x1FF;
                b0 = (int)(low >> 25) & 0x1FF;

                if (signed)
                {
                    r0 = SignExtend(r0, 9);
                    g0 = SignExtend(g0, 9);
                    b0 = SignExtend(b0, 9);
                }

                r1 = r0 + SignExtend((int)(low >> 35), 5);
                g1 = g0 + SignExtend((int)(low >> 45), 5);
                b1 = b0 + SignExtend((int)(low >> 55), 5);

                r2 = r0 + SignExtend((int)(high >> 1), 5);
                g2 = g0 + SignExtend((int)(((low >> 20) & 0x10) | ((low >> 41) & 0xF)), 5);
                b2 = b0 + SignExtend((int)(((low >> 10) & 0x10) | ((high << 3) & 8) | (low >> 61)), 5);

                r3 = r0 + SignExtend((int)(high >> 7), 5);
                g3 = g0 + SignExtend((int)(((low >> 36) & 0x10) | ((low >> 51) & 0xF)), 5);
                b3 = b0 + SignExtend((int)(
                                         ((low >> 30) & 0x10) |
                                         ((high >> 9) & 0x08) |
                                         ((high >> 4) & 0x04) |
                                         ((low >> 59) & 0x02) |
                                         ((low >> 50) & 0x01)), 5);

                r0 = Unquantize(r0, 9, signed);
                g0 = Unquantize(g0, 9, signed);
                b0 = Unquantize(b0, 9, signed);

                r1 = Unquantize(r1 & 0x1FF, 9, signed);
                g1 = Unquantize(g1 & 0x1FF, 9, signed);
                b1 = Unquantize(b1 & 0x1FF, 9, signed);

                r2 = Unquantize(r2 & 0x1FF, 9, signed);
                g2 = Unquantize(g2 & 0x1FF, 9, signed);
                b2 = Unquantize(b2 & 0x1FF, 9, signed);

                r3 = Unquantize(r3 & 0x1FF, 9, signed);
                g3 = Unquantize(g3 & 0x1FF, 9, signed);
                b3 = Unquantize(b3 & 0x1FF, 9, signed);

                subsetCount = 2;
                break;

            case 15:
                r0 = (BitReverse6((int)(low >> 39) & 0x3F) << 10) | ((int)(low >> 5) & 0x3FF);
                g0 = (BitReverse6((int)(low >> 49) & 0x3F) << 10) | ((int)(low >> 15) & 0x3FF);
                b0 = ((BitReverse6((int)(low >> 59)) | (int)(high & 1)) << 10) | ((int)(low >> 25) & 0x3FF);

                if (signed)
                {
                    r0 = SignExtend(r0, 16);
                    g0 = SignExtend(g0, 16);
                    b0 = SignExtend(b0, 16);
                }

                r1 = (r0 + SignExtend((int)(low >> 35), 4)) & 0xFFFF;
                g1 = (g0 + SignExtend((int)(low >> 45), 4)) & 0xFFFF;
                b1 = (b0 + SignExtend((int)(low >> 55), 4)) & 0xFFFF;

                subsetCount = 1;
                break;

            case 18:
                r0 = (int)(low >> 5) & 0xFF;
                g0 = (int)(low >> 15) & 0xFF;
                b0 = (int)(low >> 25) & 0xFF;

                if (signed)
                {
                    r0 = SignExtend(r0, 8);
                    g0 = SignExtend(g0, 8);
                    b0 = SignExtend(b0, 8);
                }

                r1 = r0 + SignExtend((int)(low >> 35), 6);
                g1 = g0 + SignExtend((int)(low >> 45), 5);
                b1 = b0 + SignExtend((int)(low >> 55), 5);

                r2 = r0 + SignExtend((int)(high >> 1), 6);
                g2 = g0 + SignExtend((int)(((low >> 20) & 0x10) | ((low >> 41) & 0xF)), 5);
                b2 = b0 + SignExtend((int)(((low >> 10) & 0x10) | ((high << 3) & 8) | (low >> 61)), 5);

                r3 = r0 + SignExtend((int)(high >> 7), 6);
                g3 = g0 + SignExtend((int)(((low >> 9) & 0x10) | ((low >> 51) & 0xF)), 5);
                b3 = b0 + SignExtend((int)(
                                         ((low >> 30) & 0x18) |
                                         ((low >> 21) & 0x04) |
                                         ((low >> 59) & 0x02) |
                                         ((low >> 50) & 0x01)), 5);

                r0 = Unquantize(r0, 8, signed);
                g0 = Unquantize(g0, 8, signed);
                b0 = Unquantize(b0, 8, signed);

                r1 = Unquantize(r1 & 0xFF, 8, signed);
                g1 = Unquantize(g1 & 0xFF, 8, signed);
                b1 = Unquantize(b1 & 0xFF, 8, signed);

                r2 = Unquantize(r2 & 0xFF, 8, signed);
                g2 = Unquantize(g2 & 0xFF, 8, signed);
                b2 = Unquantize(b2 & 0xFF, 8, signed);

                r3 = Unquantize(r3 & 0xFF, 8, signed);
                g3 = Unquantize(g3 & 0xFF, 8, signed);
                b3 = Unquantize(b3 & 0xFF, 8, signed);

                subsetCount = 2;
                break;

            case 22:
                r0 = (int)(low >> 5) & 0xFF;
                g0 = (int)(low >> 15) & 0xFF;
                b0 = (int)(low >> 25) & 0xFF;

                if (signed)
                {
                    r0 = SignExtend(r0, 8);
                    g0 = SignExtend(g0, 8);
                    b0 = SignExtend(b0, 8);
                }

                r1 = r0 + SignExtend((int)(low >> 35), 5);
                g1 = g0 + SignExtend((int)(low >> 45), 6);
                b1 = b0 + SignExtend((int)(low >> 55), 5);

                r2 = r0 + SignExtend((int)(high >> 1), 5);
                g2 = g0 + SignExtend((int)(((low >> 18) & 0x20) | ((low >> 20) & 0x10) | ((low >> 41) & 0xF)), 6);
                b2 = b0 + SignExtend((int)(((low >> 10) & 0x10) | ((high << 3) & 0x08) | (low >> 61)), 5);

                r3 = r0 + SignExtend((int)(high >> 7), 5);
                g3 = g0 + SignExtend((int)(((low >> 28) & 0x20) | ((low >> 36) & 0x10) | ((low >> 51) & 0x0F)), 6);
                b3 = b0 + SignExtend((int)(
                                         ((low >> 30) & 0x10) |
                                         ((high >> 9) & 0x08) |
                                         ((high >> 4) & 0x04) |
                                         ((low >> 59) & 0x02) |
                                         ((low >> 13) & 0x01)), 5);

                r0 = Unquantize(r0, 8, signed);
                g0 = Unquantize(g0, 8, signed);
                b0 = Unquantize(b0, 8, signed);

                r1 = Unquantize(r1 & 0xFF, 8, signed);
                g1 = Unquantize(g1 & 0xFF, 8, signed);
                b1 = Unquantize(b1 & 0xFF, 8, signed);

                r2 = Unquantize(r2 & 0xFF, 8, signed);
                g2 = Unquantize(g2 & 0xFF, 8, signed);
                b2 = Unquantize(b2 & 0xFF, 8, signed);

                r3 = Unquantize(r3 & 0xFF, 8, signed);
                g3 = Unquantize(g3 & 0xFF, 8, signed);
                b3 = Unquantize(b3 & 0xFF, 8, signed);

                subsetCount = 2;
                break;

            case 26:
                r0 = (int)(low >> 5) & 0xFF;
                g0 = (int)(low >> 15) & 0xFF;
                b0 = (int)(low >> 25) & 0xFF;

                if (signed)
                {
                    r0 = SignExtend(r0, 8);
                    g0 = SignExtend(g0, 8);
                    b0 = SignExtend(b0, 8);
                }

                r1 = r0 + SignExtend((int)(low >> 35), 5);
                g1 = g0 + SignExtend((int)(low >> 45), 5);
                b1 = b0 + SignExtend((int)(low >> 55), 6);

                r2 = r0 + SignExtend((int)(high >> 1), 5);
                g2 = g0 + SignExtend((int)(((low >> 20) & 0x10) | ((low >> 41) & 0xF)), 5);
                b2 = b0 + SignExtend((int)(
                                         ((low >> 18) & 0x20) |
                                         ((low >> 10) & 0x10) |
                                         ((high << 3) & 0x08) |
                                         (low >> 61)), 6);

                r3 = r0 + SignExtend((int)(high >> 7), 5);
                g3 = g0 + SignExtend((int)(((low >> 36) & 0x10) | ((low >> 51) & 0xF)), 5);
                b3 = b0 + SignExtend((int)(
                                         ((low >> 28) & 0x20) |
                                         ((low >> 30) & 0x10) |
                                         ((high >> 9) & 0x08) |
                                         ((high >> 4) & 0x04) |
                                         ((low >> 12) & 0x02) |
                                         ((low >> 50) & 0x01)), 6);

                r0 = Unquantize(r0, 8, signed);
                g0 = Unquantize(g0, 8, signed);
                b0 = Unquantize(b0, 8, signed);

                r1 = Unquantize(r1 & 0xFF, 8, signed);
                g1 = Unquantize(g1 & 0xFF, 8, signed);
                b1 = Unquantize(b1 & 0xFF, 8, signed);

                r2 = Unquantize(r2 & 0xFF, 8, signed);
                g2 = Unquantize(g2 & 0xFF, 8, signed);
                b2 = Unquantize(b2 & 0xFF, 8, signed);

                r3 = Unquantize(r3 & 0xFF, 8, signed);
                g3 = Unquantize(g3 & 0xFF, 8, signed);
                b3 = Unquantize(b3 & 0xFF, 8, signed);

                subsetCount = 2;
                break;

            case 30:
                r0 = (int)(low >> 5) & 0x3F;
                g0 = (int)(low >> 15) & 0x3F;
                b0 = (int)(low >> 25) & 0x3F;

                r1 = (int)(low >> 35) & 0x3F;
                g1 = (int)(low >> 45) & 0x3F;
                b1 = (int)(low >> 55) & 0x3F;

                r2 = (int)(high >> 1) & 0x3F;
                g2 = (int)(((low >> 16) & 0x20) | ((low >> 20) & 0x10) | ((low >> 41) & 0xF));
                b2 = (int)(((low >> 17) & 0x20) | ((low >> 10) & 0x10) | ((high << 3) & 0x08) | (low >> 61));

                r3 = (int)(high >> 7) & 0x3F;
                g3 = (int)(((low >> 26) & 0x20) | ((low >> 7) & 0x10) | ((low >> 51) & 0xF));
                b3 = (int)(
                    ((low >> 28) & 0x20) |
                    ((low >> 30) & 0x10) |
                    ((low >> 29) & 0x08) |
                    ((low >> 21) & 0x04) |
                    ((low >> 12) & 0x03));

                if (signed)
                {
                    r0 = SignExtend(r0, 6);
                    g0 = SignExtend(g0, 6);
                    b0 = SignExtend(b0, 6);

                    r1 = SignExtend(r1, 6);
                    g1 = SignExtend(g1, 6);
                    b1 = SignExtend(b1, 6);

                    r2 = SignExtend(r2, 6);
                    g2 = SignExtend(g2, 6);
                    b2 = SignExtend(b2, 6);

                    r3 = SignExtend(r3, 6);
                    g3 = SignExtend(g3, 6);
                    b3 = SignExtend(b3, 6);
                }

                r0 = Unquantize(r0, 6, signed);
                g0 = Unquantize(g0, 6, signed);
                b0 = Unquantize(b0, 6, signed);

                r1 = Unquantize(r1, 6, signed);
                g1 = Unquantize(g1, 6, signed);
                b1 = Unquantize(b1, 6, signed);

                r2 = Unquantize(r2, 6, signed);
                g2 = Unquantize(g2, 6, signed);
                b2 = Unquantize(b2, 6, signed);

                r3 = Unquantize(r3, 6, signed);
                g3 = Unquantize(g3, 6, signed);
                b3 = Unquantize(b3, 6, signed);

                subsetCount = 2;
                break;

            default:
                subsetCount = 0;
                break;
            }

            if (subsetCount > 0)
            {
                endPoints[0] = new RgbaColor32(r0, g0, b0, HalfOne);
                endPoints[1] = new RgbaColor32(r1, g1, b1, HalfOne);

                if (subsetCount > 1)
                {
                    endPoints[2] = new RgbaColor32(r2, g2, b2, HalfOne);
                    endPoints[3] = new RgbaColor32(r3, g3, b3, HalfOne);
                }
            }

            return(subsetCount);
        }