예제 #1
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();
                }
            }
        }
예제 #2
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;
                }
            }
        }