예제 #1
0
        public ArgbSurface(SurfaceData surfaceData, bool alphaPremultiplied = false)
            : base(surfaceData.Width, surfaceData.Height, 8, alphaPremultiplied)
        {
            int rowLength = sizeof(uint) * Width;
            int dataLength = rowLength * Height;

            if (surfaceData.Stride < rowLength) throw new ArgumentException();

            data = new byte[dataLength];

            unsafe
            {
                fixed (byte* dataPointer = data)
                {
                    byte* destinationRowPointer = dataPointer;
                    byte* sourceRowPointer = (byte*)surfaceData.DataPointer;

                    for (int i = Height; i-- != 0; destinationRowPointer += rowLength, sourceRowPointer += surfaceData.Stride)
                    {
                        ArgbColor* destinationPointer = (ArgbColor*)destinationRowPointer;
                        ArgbColor* sourcePointer = (ArgbColor*)sourceRowPointer;

                        for (int j = Width; j-- != 0; ) *destinationPointer++ = *sourcePointer++;
                    }
                }
            }
        }
예제 #2
0
파일: Surface.cs 프로젝트: Bootz/crystalmpq
        /// <summary>Copies the contents of the surface to a buffer of same dimensions.</summary>
        /// <remarks>
        /// The destination buffer should use the ARGB format represented by <see cref="ArgbColor"/>.
        /// Some basic checks will be done to disallow invalid buffer informations.
        /// However, it is the responsibility of the caller to provide a valid destination buffer.
        /// </remarks>
        /// <param name="surfaceData">Information on the destination buffer.</param>
        /// <exception cref="ArgumentException">The dimensions of the buffer specified by <paramref name="surfaceData"/> do not match those of the surface.</exception>
        /// <exception cref="InvalidOperationException">The stride in <paramref name="surfaceData"/> does not match the width.</exception>
        public void CopyToArgb(SurfaceData surfaceData)
        {
            if (surfaceData.Width != width || surfaceData.Height != height)
            {
                throw new ArgumentException();
            }
            if (surfaceData.Stride < sizeof(uint) * surfaceData.Width)
            {
                throw new InvalidOperationException();
            }

            CopyToArgbInternal(surfaceData);
        }
예제 #3
0
        private unsafe void CopyToArgbAlpha8(SurfaceData surfaceData)
        {
            fixed(byte *dataPointer = data)
            fixed(ArgbColor * palettePointer = palette)
            {
                byte *destinationRowPointer = (byte *)surfaceData.DataPointer;
                byte *sourceColorPointer    = dataPointer;
                byte *sourceAlphaPointer    = dataPointer + Width * Height;

                for (int i = Height; i-- != 0; destinationRowPointer += surfaceData.Stride)
                {
                    ArgbColor *destinationPointer = (ArgbColor *)destinationRowPointer;

                    for (int j = Width; j-- != 0;)
                    {
                        ArgbColor.CopyWithAlpha(destinationPointer++, palettePointer + *sourceColorPointer++, *sourceAlphaPointer++);
                    }
                }
            }
        }
예제 #4
0
        private unsafe void CopyToArgbTransparent(SurfaceData surfaceData)
        {
            int rowLength = Width;

            fixed(byte *dataPointer = data)
            fixed(ArgbColor * palettePointer = palette)
            {
                byte *destinationRowPointer = (byte *)surfaceData.DataPointer;
                byte *sourcePointer         = dataPointer;

                for (int i = Height; i-- != 0; destinationRowPointer += surfaceData.Stride)
                {
                    ArgbColor *destinationPointer = (ArgbColor *)destinationRowPointer;

                    for (int j = Width; j-- != 0;)
                    {
                        *destinationPointer++ = palettePointer[*sourcePointer++];
                    }
                }
            }
        }
예제 #5
0
        protected unsafe override void CopyToArgbInternal(SurfaceData surfaceData)
        {
            int rowLength = sizeof(uint) * Width;

            fixed(byte *dataPointer = data)
            {
                byte *destinationRowPointer = (byte *)surfaceData.DataPointer;
                byte *sourceRowPointer      = dataPointer;

                for (int i = Height; i-- != 0; destinationRowPointer += surfaceData.Stride, sourceRowPointer += rowLength)
                {
                    ArgbColor *destinationPointer = (ArgbColor *)destinationRowPointer;
                    ArgbColor *sourcePointer      = (ArgbColor *)sourceRowPointer;

                    for (int j = Width; j-- != 0;)
                    {
                        *destinationPointer++ = *sourcePointer++;
                    }
                }
            }
        }
예제 #6
0
        protected unsafe override void CopyToArgbInternal(SurfaceData surfaceData)
        {
            switch (AlphaBitCount)
            {
            case 0: CopyToArgbOpaque(surfaceData); break;

            case 1: CopyToArgbAlpha1(surfaceData); break;

            case 4: CopyToArgbAlpha4(surfaceData); break;

            case 8: if (separateAlpha)
                {
                    CopyToArgbAlpha8(surfaceData);
                }
                else
                {
                    CopyToArgbTransparent(surfaceData);
                } break;

            default: throw new NotSupportedException();                     // Should never happen…
            }
        }
예제 #7
0
파일: Surface.cs 프로젝트: Bootz/crystalmpq
 protected abstract void CopyToArgbInternal(SurfaceData surfaceData);
예제 #8
0
 protected override void CopyToArgbInternal(SurfaceData surfaceData)
 {
     throw new NotSupportedException();
 }
예제 #9
0
        protected unsafe override void CopyToArgbInternal(SurfaceData surfaceData)
        {
            var colors = stackalloc ArgbColor[4];
            var alpha = stackalloc byte[8];

            fixed (byte* dataPointer = data)
            {
                var destinationRowPointer = (byte*)surfaceData.DataPointer;
                var sourcePointer = dataPointer;
                int rowBlockStride = surfaceData.Stride << 2;

                for (int i = Height; i > 0; i -= 4, destinationRowPointer += rowBlockStride)
                {
                    var destinationPointer = destinationRowPointer;

                    for (int j = Width; j > 0; j -= 4)
                    {
                        alpha[0] = *sourcePointer++;
                        alpha[1] = *sourcePointer++;

                        // The divisions here have been optimized with multiply/shift
                        // Maybe there is way for some optimization in the multiplications, (using shifts and additions/substractions where applicable)
                        // but for now I just hope the .NET JIT knows how to do those optimizations when they are possible…
                        if (alpha[0] <= alpha[1])
                        {
                            alpha[2] = (byte)((4 * alpha[0] + alpha[1]) * 1639 >> 13);
                            alpha[3] = (byte)((3 * alpha[0] + 2 * alpha[1]) * 1639 >> 13);
                            alpha[4] = (byte)((2 * alpha[0] + 3 * alpha[1]) * 1639 >> 13);
                            alpha[5] = (byte)((alpha[0] + 4 * alpha[1]) * 1639 >> 13);
                            alpha[6] = 0;
                            alpha[7] = 255;
                        }
                        else
                        {
                            alpha[2] = (byte)((6 * alpha[0] + alpha[1]) * 2341 >> 14);
                            alpha[3] = (byte)((5 * alpha[0] + 2 * alpha[1]) * 2341 >> 14);
                            alpha[4] = (byte)((4 * alpha[0] + 3 * alpha[1]) * 2341 >> 14);
                            alpha[5] = (byte)((3 * alpha[0] + 4 * alpha[1]) * 2341 >> 14);
                            alpha[6] = (byte)((2 * alpha[0] + 5 * alpha[1]) * 2341 >> 14);
                            alpha[7] = (byte)((alpha[0] + 6 * alpha[1]) * 2341 >> 14);
                        }

                        // Store the block's alpha data in a 64 bit integer. This will probably be a bit slower on 32-bit CPUs, but who cares… :p
                        ulong blockAlphaData = (ulong)(*sourcePointer++ | (uint)*sourcePointer++ << 8 | (uint)*sourcePointer++ << 16 | (uint)*sourcePointer++ << 24) | (ulong)(*sourcePointer++ | (uint)*sourcePointer++ << 8) << 32;

                        ushort color0 = (ushort)(*sourcePointer++ | *sourcePointer++ << 8);
                        ushort color1 = (ushort)(*sourcePointer++ | *sourcePointer++ << 8);

                        colors[0] = new ArgbColor(color0);
                        colors[1] = new ArgbColor(color1);

                        ArgbColor.DxtMergeThirds(colors + 2, colors + 1, colors);
                        ArgbColor.DxtMergeThirds(colors + 3, colors, colors + 1);

                        // Handle the case where the surface's width is not a multiple of 4.
                        int inverseBlockWidth = j > 4 ? 0 : 4 - j;

                        var blockRowDestinationPointer = destinationPointer;

                        for (int k = 4; k-- != 0; blockRowDestinationPointer += surfaceData.Stride)
                        {
                            byte rowData = *sourcePointer++;

                            if (i + k < 4) continue; // Handle the case where the surface's height is not a multiple of 4.

                            var blockDestinationPointer = (ArgbColor*)blockRowDestinationPointer;

                            if (inverseBlockWidth != 0) blockAlphaData >>= 3 * inverseBlockWidth;

                            // The small loop here has been unrolled, which shoudl be well worth it:
                            //  - No loop variable is needed.
                            //  - No useless shift and incrementation for the last step.
                            //  - Only one conditional jump.
                            //  - The loop will be executed very often, as the blocks are very small.
                            switch (inverseBlockWidth)
                            {
                                case 0:
                                    ArgbColor.CopyWithAlpha(blockDestinationPointer++, &colors[rowData & 3], alpha[blockAlphaData & 7]);
                                    rowData >>= 2;
                                    blockAlphaData >>= 3;
                                    goto case 1;
                                case 1:
                                    ArgbColor.CopyWithAlpha(blockDestinationPointer++, &colors[rowData & 3], alpha[blockAlphaData & 7]);
                                    rowData >>= 2;
                                    blockAlphaData >>= 3;
                                    goto case 2;
                                case 2:
                                    ArgbColor.CopyWithAlpha(blockDestinationPointer++, &colors[rowData & 3], alpha[blockAlphaData & 7]);
                                    rowData >>= 2;
                                    blockAlphaData >>= 3;
                                    goto case 3;
                                case 3:
                                    ArgbColor.CopyWithAlpha(blockDestinationPointer, &colors[rowData & 3], alpha[blockAlphaData & 7]);
                                    blockAlphaData >>= 3;
                                    break;
                            }
                        }

                        destinationPointer += 4 * sizeof(uint); // Skip the 4 processed pixels
                    }
                }
            }
        }
예제 #10
0
        protected unsafe override void CopyToArgbInternal(SurfaceData surfaceData)
        {
            var colors = stackalloc ArgbColor[4];

            fixed (byte* dataPointer = data)
            {
                var destinationRowPointer = (byte*)surfaceData.DataPointer;
                var sourcePointer = dataPointer;
                int rowBlockStride = surfaceData.Stride << 2;

                for (int i = Height; i > 0; i -= 4, destinationRowPointer += rowBlockStride)
                {
                    var destinationPointer = destinationRowPointer;

                    for (int j = Width; j > 0; j -= 4)
                    {
                        var alphaPointer = (ushort*)sourcePointer; // Save the alpha block pointer for later

                        sourcePointer += 8; // Get to the color block

                        ushort color0 = (ushort)(*sourcePointer++ | *sourcePointer++ << 8);
                        ushort color1 = (ushort)(*sourcePointer++ | *sourcePointer++ << 8);

                        colors[0] = new ArgbColor(color0);
                        colors[1] = new ArgbColor(color1);
                        ArgbColor.DxtMergeThirds(colors + 2, colors + 1, colors);
                        ArgbColor.DxtMergeThirds(colors + 3, colors, colors + 1);

                        // Handle the case where the surface's width is not a multiple of 4.
                        int inverseBlockWidth = j > 4 ? 0 : 4 - j;

                        var blockRowDestinationPointer = destinationPointer;

                        for (int k = 4; k-- != 0; blockRowDestinationPointer += surfaceData.Stride)
                        {
                            byte rowData = *sourcePointer++;

                            if (i + k < 4) continue; // Handle the case where the surface's height is not a multiple of 4.

                            var blockDestinationPointer = (ArgbColor*)blockRowDestinationPointer;

                            // The small loop here has been unrolled, which should be well worth it:
                            //  - No loop variable is needed.
                            //  - No useless shift and incrementation for the last step.
                            //  - Only one conditional jump.
                            //  - The loop will be executed very often, as the blocks are very small.
                            switch (inverseBlockWidth)
                            {
                                case 0:
                                    ArgbColor.CopyWithAlpha(blockDestinationPointer++, &colors[rowData & 3], (byte)(*alphaPointer << 4));
                                    rowData >>= 2;
                                    goto case 1;
                                case 1:
                                    ArgbColor.CopyWithAlpha(blockDestinationPointer++, &colors[rowData & 3], (byte)(*alphaPointer & 0xF0));
                                    rowData >>= 2;
                                    goto case 2;
                                case 2:
                                    ArgbColor.CopyWithAlpha(blockDestinationPointer++, &colors[rowData & 3], (byte)((*alphaPointer >> 4) & 0xF0));
                                    rowData >>= 2;
                                    goto case 3;
                                case 3:
                                    ArgbColor.CopyWithAlpha(blockDestinationPointer, &colors[rowData & 3], (byte)((*alphaPointer++ >> 8) & 0xF0));
                                    break;
                            }
                        }

                        destinationPointer += 4 * sizeof(uint); // Skip the 4 processed pixels
                    }
                }
            }
        }
예제 #11
0
 protected override void CopyToArgbInternal(SurfaceData surfaceData)
 {
     throw new NotSupportedException();
 }
예제 #12
0
 protected override sealed void CopyToArgbInternal(SurfaceData surfaceData)
 {
     @this.CopyToArgbInternal(surfaceData);
 }
예제 #13
0
        private unsafe void CopyToArgbAlpha1(SurfaceData surfaceData)
        {
            fixed (byte* dataPointer = data)
            fixed (ArgbColor* palettePointer = palette)
            {
                byte* destinationRowPointer = (byte*)surfaceData.DataPointer;
                byte* sourceColorPointer = dataPointer;
                byte* sourceAlphaPointer = dataPointer + Width * Height;
                byte alphaData = 0;
                byte alphaState = 0;

                for (int i = Height; i-- != 0; destinationRowPointer += surfaceData.Stride)
                {
                    ArgbColor* destinationPointer = (ArgbColor*)destinationRowPointer;

                    for (int j = Width; j-- != 0; alphaState--, alphaData >>= 1)
                    {
                        if (alphaState == 0)
                        {
                            alphaState = 8;
                            alphaData = *sourceAlphaPointer++;
                        }

                        ArgbColor.CopyWithAlpha(destinationPointer++, palettePointer + *sourceColorPointer++, (alphaData & 1) != 0 ? (byte)255 : (byte)0);
                    }
                }
            }
        }
예제 #14
0
        /// <summary>Copies the contents of the surface to a buffer of same dimensions.</summary>
        /// <remarks>
        /// The destination buffer should use the ARGB format represented by <see cref="ArgbColor"/>.
        /// Some basic checks will be done to disallow invalid buffer informations.
        /// However, it is the responsibility of the caller to provide a valid destination buffer.
        /// </remarks>
        /// <param name="surfaceData">Information on the destination buffer.</param>
        /// <exception cref="ArgumentException">The dimensions of the buffer specified by <paramref name="surfaceData"/> do not match those of the surface.</exception>
        /// <exception cref="InvalidOperationException">The stride in <paramref name="surfaceData"/> does not match the width.</exception>
        public void CopyToArgb(SurfaceData surfaceData)
        {
            if (surfaceData.Width != width || surfaceData.Height != height) throw new ArgumentException();
            if (surfaceData.Stride < sizeof(uint) * surfaceData.Width) throw new InvalidOperationException();

            CopyToArgbInternal(surfaceData);
        }
예제 #15
0
        protected unsafe override void CopyToArgbInternal(SurfaceData surfaceData)
        {
            var colors = stackalloc ArgbColor[4];
            var alpha  = stackalloc byte[8];

            fixed(byte *dataPointer = data)
            {
                var destinationRowPointer = (byte *)surfaceData.DataPointer;
                var sourcePointer         = dataPointer;
                int rowBlockStride        = surfaceData.Stride << 2;

                for (int i = Height; i > 0; i -= 4, destinationRowPointer += rowBlockStride)
                {
                    var destinationPointer = destinationRowPointer;

                    for (int j = Width; j > 0; j -= 4)
                    {
                        alpha[0] = *sourcePointer++;
                        alpha[1] = *sourcePointer++;

                        // The divisions here have been optimized with multiply/shift
                        // Maybe there is way for some optimization in the multiplications, (using shifts and additions/substractions where applicable)
                        // but for now I just hope the .NET JIT knows how to do those optimizations when they are possible…
                        if (alpha[0] <= alpha[1])
                        {
                            alpha[2] = (byte)((4 * alpha[0] + alpha[1]) * 1639 >> 13);
                            alpha[3] = (byte)((3 * alpha[0] + 2 * alpha[1]) * 1639 >> 13);
                            alpha[4] = (byte)((2 * alpha[0] + 3 * alpha[1]) * 1639 >> 13);
                            alpha[5] = (byte)((alpha[0] + 4 * alpha[1]) * 1639 >> 13);
                            alpha[6] = 0;
                            alpha[7] = 255;
                        }
                        else
                        {
                            alpha[2] = (byte)((6 * alpha[0] + alpha[1]) * 2341 >> 14);
                            alpha[3] = (byte)((5 * alpha[0] + 2 * alpha[1]) * 2341 >> 14);
                            alpha[4] = (byte)((4 * alpha[0] + 3 * alpha[1]) * 2341 >> 14);
                            alpha[5] = (byte)((3 * alpha[0] + 4 * alpha[1]) * 2341 >> 14);
                            alpha[6] = (byte)((2 * alpha[0] + 5 * alpha[1]) * 2341 >> 14);
                            alpha[7] = (byte)((alpha[0] + 6 * alpha[1]) * 2341 >> 14);
                        }

                        // Store the block's alpha data in a 64 bit integer. This will probably be a bit slower on 32-bit CPUs, but who cares… :p
                        ulong blockAlphaData = (ulong)(*sourcePointer++ | (uint)*sourcePointer++ << 8 | (uint)*sourcePointer++ << 16 | (uint)*sourcePointer++ << 24) | (ulong)(*sourcePointer++ | (uint)*sourcePointer++ << 8) << 32;

                        ushort color0 = (ushort)(*sourcePointer++ | *sourcePointer++ << 8);
                        ushort color1 = (ushort)(*sourcePointer++ | *sourcePointer++ << 8);

                        colors[0] = new ArgbColor(color0);
                        colors[1] = new ArgbColor(color1);

                        ArgbColor.DxtMergeThirds(colors + 2, colors + 1, colors);
                        ArgbColor.DxtMergeThirds(colors + 3, colors, colors + 1);

                        // Handle the case where the surface's width is not a multiple of 4.
                        int inverseBlockWidth = j > 4 ? 0 : 4 - j;

                        var blockRowDestinationPointer = destinationPointer;

                        for (int k = 4; k-- != 0; blockRowDestinationPointer += surfaceData.Stride)
                        {
                            byte rowData = *sourcePointer++;

                            if (i + k < 4)
                            {
                                continue;                                        // Handle the case where the surface's height is not a multiple of 4.
                            }
                            var blockDestinationPointer = (ArgbColor *)blockRowDestinationPointer;

                            if (inverseBlockWidth != 0)
                            {
                                blockAlphaData >>= 3 * inverseBlockWidth;
                            }

                            // The small loop here has been unrolled, which shoudl be well worth it:
                            //  - No loop variable is needed.
                            //  - No useless shift and incrementation for the last step.
                            //  - Only one conditional jump.
                            //  - The loop will be executed very often, as the blocks are very small.
                            switch (inverseBlockWidth)
                            {
                            case 0:
                                ArgbColor.CopyWithAlpha(blockDestinationPointer++, &colors[rowData & 3], alpha[blockAlphaData & 7]);
                                rowData        >>= 2;
                                blockAlphaData >>= 3;
                                goto case 1;

                            case 1:
                                ArgbColor.CopyWithAlpha(blockDestinationPointer++, &colors[rowData & 3], alpha[blockAlphaData & 7]);
                                rowData        >>= 2;
                                blockAlphaData >>= 3;
                                goto case 2;

                            case 2:
                                ArgbColor.CopyWithAlpha(blockDestinationPointer++, &colors[rowData & 3], alpha[blockAlphaData & 7]);
                                rowData        >>= 2;
                                blockAlphaData >>= 3;
                                goto case 3;

                            case 3:
                                ArgbColor.CopyWithAlpha(blockDestinationPointer, &colors[rowData & 3], alpha[blockAlphaData & 7]);
                                blockAlphaData >>= 3;
                                break;
                            }
                        }

                        destinationPointer += 4 * sizeof(uint);                         // Skip the 4 processed pixels
                    }
                }
            }
        }
예제 #16
0
        protected unsafe override void CopyToArgbInternal(SurfaceData surfaceData)
        {
            int rowLength = sizeof(uint) * Width;

            fixed (byte* dataPointer = data)
            {
                byte* destinationRowPointer = (byte*)surfaceData.DataPointer;
                byte* sourceRowPointer = dataPointer;

                for (int i = Height; i-- != 0; destinationRowPointer += surfaceData.Stride, sourceRowPointer += rowLength)
                {
                    ArgbColor* destinationPointer = (ArgbColor*)destinationRowPointer;
                    ArgbColor* sourcePointer = (ArgbColor*)sourceRowPointer;

                    for (int j = Width; j-- != 0; ) *destinationPointer++ = *sourcePointer++;
                }
            }
        }
예제 #17
0
        private unsafe void CopyToArgbTransparent(SurfaceData surfaceData)
        {
            int rowLength = Width;

            fixed (byte* dataPointer = data)
            fixed (ArgbColor* palettePointer = palette)
            {
                byte* destinationRowPointer = (byte*)surfaceData.DataPointer;
                byte* sourcePointer = dataPointer;

                for (int i = Height; i-- != 0; destinationRowPointer += surfaceData.Stride)
                {
                    ArgbColor* destinationPointer = (ArgbColor*)destinationRowPointer;

                    for (int j = Width; j-- != 0; ) *destinationPointer++ = palettePointer[*sourcePointer++];
                }
            }
        }
예제 #18
0
        private unsafe void CopyToArgbAlpha8(SurfaceData surfaceData)
        {
            fixed (byte* dataPointer = data)
            fixed (ArgbColor* palettePointer = palette)
            {
                byte* destinationRowPointer = (byte*)surfaceData.DataPointer;
                byte* sourceColorPointer = dataPointer;
                byte* sourceAlphaPointer = dataPointer + Width * Height;

                for (int i = Height; i-- != 0; destinationRowPointer += surfaceData.Stride)
                {
                    ArgbColor* destinationPointer = (ArgbColor*)destinationRowPointer;

                    for (int j = Width; j-- != 0; ) ArgbColor.CopyWithAlpha(destinationPointer++, palettePointer + *sourceColorPointer++, *sourceAlphaPointer++);
                }
            }
        }
예제 #19
0
        private unsafe void CopyToArgbAlpha4(SurfaceData surfaceData)
        {
            // Use a precalculated alpha table for very fast conversions.
            var alphaTable = stackalloc byte[16];
            for (int i = 0; i < 16; i++) alphaTable[i] = (byte)(i * (255 * 2185) >> 15); // x / 15 = x * 2185 >> 15 (for 0 ≤ x ≤ 15 * 255)

            fixed (byte* dataPointer = data)
            fixed (ArgbColor* palettePointer = palette)
            {
                byte* destinationRowPointer = (byte*)surfaceData.DataPointer;
                byte* sourceColorPointer = dataPointer;
                byte* sourceAlphaPointer = dataPointer + Width * Height;
                byte alphaData = 0;
                bool alphaState = false;

                for (int i = Height; i-- != 0; destinationRowPointer += surfaceData.Stride)
                {
                    ArgbColor* destinationPointer = (ArgbColor*)destinationRowPointer;

                    for (int j = Width; j-- != 0; )
                        ArgbColor.CopyWithAlpha(destinationPointer++, palettePointer + *sourceColorPointer++, alphaTable[(alphaState = !alphaState) ? (alphaData = *sourceAlphaPointer++) & 0xF : alphaData >> 4]);
                }
            }
        }
예제 #20
0
파일: Surface.cs 프로젝트: Bootz/crystalmpq
 protected sealed override void CopyToArgbInternal(SurfaceData surfaceData)
 {
     @this.CopyToArgbInternal(surfaceData);
 }
예제 #21
0
 protected abstract void CopyToArgbInternal(SurfaceData surfaceData);
예제 #22
0
        protected unsafe override void CopyToArgbInternal(SurfaceData surfaceData)
        {
            var colors = stackalloc ArgbColor[4];

            fixed(byte *dataPointer = data)
            {
                var destinationRowPointer = (byte *)surfaceData.DataPointer;
                var sourcePointer         = dataPointer;
                int rowBlockStride        = surfaceData.Stride << 2;

                for (int i = Height; i > 0; i -= 4, destinationRowPointer += rowBlockStride)
                {
                    var destinationPointer = destinationRowPointer;

                    for (int j = Width; j > 0; j -= 4)
                    {
                        var alphaPointer = (ushort *)sourcePointer; // Save the alpha block pointer for later

                        sourcePointer += 8;                         // Get to the color block

                        ushort color0 = (ushort)(*sourcePointer++ | *sourcePointer++ << 8);
                        ushort color1 = (ushort)(*sourcePointer++ | *sourcePointer++ << 8);

                        colors[0] = new ArgbColor(color0);
                        colors[1] = new ArgbColor(color1);
                        ArgbColor.DxtMergeThirds(colors + 2, colors + 1, colors);
                        ArgbColor.DxtMergeThirds(colors + 3, colors, colors + 1);

                        // Handle the case where the surface's width is not a multiple of 4.
                        int inverseBlockWidth = j > 4 ? 0 : 4 - j;

                        var blockRowDestinationPointer = destinationPointer;

                        for (int k = 4; k-- != 0; blockRowDestinationPointer += surfaceData.Stride)
                        {
                            byte rowData = *sourcePointer++;

                            if (i + k < 4)
                            {
                                continue;                                        // Handle the case where the surface's height is not a multiple of 4.
                            }
                            var blockDestinationPointer = (ArgbColor *)blockRowDestinationPointer;

                            // The small loop here has been unrolled, which should be well worth it:
                            //  - No loop variable is needed.
                            //  - No useless shift and incrementation for the last step.
                            //  - Only one conditional jump.
                            //  - The loop will be executed very often, as the blocks are very small.
                            switch (inverseBlockWidth)
                            {
                            case 0:
                                ArgbColor.CopyWithAlpha(blockDestinationPointer++, &colors[rowData & 3], (byte)(*alphaPointer << 4));
                                rowData >>= 2;
                                goto case 1;

                            case 1:
                                ArgbColor.CopyWithAlpha(blockDestinationPointer++, &colors[rowData & 3], (byte)(*alphaPointer & 0xF0));
                                rowData >>= 2;
                                goto case 2;

                            case 2:
                                ArgbColor.CopyWithAlpha(blockDestinationPointer++, &colors[rowData & 3], (byte)((*alphaPointer >> 4) & 0xF0));
                                rowData >>= 2;
                                goto case 3;

                            case 3:
                                ArgbColor.CopyWithAlpha(blockDestinationPointer, &colors[rowData & 3], (byte)((*alphaPointer++ >> 8) & 0xF0));
                                break;
                            }
                        }

                        destinationPointer += 4 * sizeof(uint);                         // Skip the 4 processed pixels
                    }
                }
            }
        }
예제 #23
0
 protected unsafe override void CopyToArgbInternal(SurfaceData surfaceData)
 {
     switch (AlphaBitCount)
     {
         case 0: CopyToArgbOpaque(surfaceData); break;
         case 1: CopyToArgbAlpha1(surfaceData); break;
         case 4: CopyToArgbAlpha4(surfaceData); break;
         case 8: if (separateAlpha) CopyToArgbAlpha8(surfaceData); else CopyToArgbTransparent(surfaceData); break;
         default: throw new NotSupportedException(); // Should never happen…
     }
 }