protected override bool TryCopyFrom(
            BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
        {
            if (!sourceBitmap.TryGetFormat(out SurfaceFormat sourceFormat))
            {
                return(false);
            }

            TryGetFormat(out SurfaceFormat format);

            // A shortcut for copying the entire bitmap to another bitmap of the same type and format
            if (format == sourceFormat &&
                sourceRegion == new Rectangle(0, 0, Width, Height) &&
                sourceRegion == destinationRegion)
            {
                SetPixelData(sourceBitmap.GetPixelData());
                return(true);
            }

            // Destination region copy is not yet supported
            if (destinationRegion != new Rectangle(0, 0, Width, Height))
            {
                return(false);
            }

            if (sourceBitmap is PixelBitmapContent <RgbaVector> &&
                sourceRegion.Width == destinationRegion.Width &&
                sourceRegion.Height == destinationRegion.Height)
            {
                ATICompressor.CompressionFormat targetFormat;
                switch (format)
                {
                case SurfaceFormat.RgbaAtcExplicitAlpha:
                    targetFormat = ATICompressor.CompressionFormat.AtcRgbaExplicitAlpha;
                    break;

                case SurfaceFormat.RgbaAtcInterpolatedAlpha:
                    targetFormat = ATICompressor.CompressionFormat.AtcRgbaInterpolatedAlpha;
                    break;

                default:
                    return(false);
                }

                var sourceData     = sourceBitmap.GetPixelData();
                var compressedData = ATICompressor.Compress(sourceData, Width, Height, targetFormat);
                SetPixelData(compressedData);
                return(true);
            }
            try
            {
                Copy(sourceBitmap, sourceRegion, this, destinationRegion);
                return(true);
            }
            catch (InvalidOperationException)
            {
                return(false);
            }
        }
        public void TestRGBToETC1Compression()
        {
            byte[] data = new byte[128 * 128 * 4];
            for (int i = 0; i < data.Length; i++)
            {
                data [i] = (i % 2) == 0 ? (byte)0 : (byte)1;
            }
            var output = ATICompressor.Compress(data, 128, 128, ATICompressor.CompressionFormat.Etc1);

            Assert.AreEqual(8192, output.Length, "Compressed data was not the correct length");
        }
        public void TestRGBAToATITCCompression()
        {
            byte[] data = new byte[128 * 128 * 4];
            for (int i = 0; i < data.Length; i++)
            {
                data [i] = (i % 2) == 0 ? (byte)0 : (byte)1;
            }
            var output = ATICompressor.Compress(data, 128, 128, ATICompressor.CompressionFormat.AtcRgbaExplicitAlpha);

            Assert.AreEqual(16384, output.Length, "Compressed data was not the correct length");
        }
Example #4
0
        /// <summary>
        /// Compress Texture from RGBA32 to dest byte arrays
        /// </summary>
        /// <param name="format">Texture2D TextureFormat</param>
        /// <param name="width">Texture2D width</param>
        /// <param name="height">Texture2D height</param>
        /// <param name="sourceData">RGBA32 source data 8bit per channel {R8:G8:B8:A8}</param>
        /// <param name="output">dest byte arrays</param>
        /// <returns></returns>
        public static bool CompressTexture(TextureFormat format, int width, int height, byte[] sourceData, out byte[] output)
        {
            bool result = true;
            int  pos;
            int  outPos;

            output = new byte[] { };
            switch (format)
            {
            case TextureFormat.Alpha8:
                output = new byte[width * height];
                pos    = 0;
                outPos = 0;
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        var fR = sourceData[pos];
                        var fG = sourceData[pos + 1];
                        var fB = sourceData[pos + 2];
                        var fA = sourceData[pos + 3];
                        output[outPos] = (byte)(((fR + fB + fG) / 3) & 0XFF);
                        pos           += 4;
                        outPos        += 1;
                    }
                }
                break;

            case TextureFormat.ARGB4444:
                output = new byte[width * height * 2];
                using (var pvrTexture = PVRTexLibNET.PVRTexture.CreateTexture(sourceData, (uint)width, (uint)height, 1, PVRTexLibNET.PixelFormat.RGBA8888, true, VariableType.UnsignedByte, ColourSpace.sRGB))
                {
                    bool bDoDither = true;    //降色抖动算法
                    pvrTexture.Transcode(PVRTexLibNET.PixelFormat.RGBA4444, VariableType.UnsignedByte, ColourSpace.sRGB, CompressorQuality.PVRTCNormal, bDoDither);
                    var texDataSize = pvrTexture.GetTextureDataSize(0);
                    var texData     = new byte[texDataSize];
                    pvrTexture.GetTextureData(texData, texDataSize);     // texData 是 {A ,B , G, R}结构的像素字节数组,和传入的相反
                    output = new byte[texDataSize];
                    // Unity 的ARGB4444需要的是{B , G, R, A}的数组,所以需要交换通道
                    pos    = 0;
                    outPos = 0;
                    for (int y = 0; y < height; y++)
                    {
                        for (int x = 0; x < width; x++)
                        {
                            var v0 = texData[pos];
                            var v1 = texData[pos + 1];
                            // 4bit little endian {A, B},{G, R}
                            var sA = v0 & 0xF0 >> 4;
                            var sB = (v0 & 0xF0) >> 4;
                            var sG = v1 & 0xF0 >> 4;
                            var sR = (v1 & 0xF0) >> 4;
                            // swap to little endian {B, G, R, A }
                            // Unity早版本还有一种 R, G,B, A的格式,需要再次swap
                            var fB = sB & 0xf;
                            var fG = sG & 0xf;
                            var fR = sR & 0xf;
                            var fA = sA & 0xf;


                            output[outPos]     = (byte)((fG << 4) + fB);
                            output[outPos + 1] = (byte)((fA << 4) + fR);
                            pos    += 2;
                            outPos += 2;
                        }
                    }
                    result = true;
                }
                break;

            case TextureFormat.RGB565:
                using (var pvrTexture = PVRTexLibNET.PVRTexture.CreateTexture(sourceData, (uint)width, (uint)height, 1, PVRTexLibNET.PixelFormat.RGBA8888, true, VariableType.UnsignedByte, ColourSpace.sRGB))
                {
                    bool bDoDither = true;
                    pvrTexture.Transcode(PVRTexLibNET.PixelFormat.RGB565, VariableType.UnsignedByte, ColourSpace.sRGB, CompressorQuality.ETCMedium, bDoDither);
                    var texDataSize = pvrTexture.GetTextureDataSize(0);
                    var texData     = new byte[texDataSize];
                    pvrTexture.GetTextureData(texData, texDataSize);
                    output = texData;
                    result = true;
                }
                break;

            case TextureFormat.RGB24:
                pos    = 0;
                outPos = 0;
                output = new byte[width * height * 3];
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        // 4bit little endian {A, B},{G, R}
                        var sR = sourceData[pos];
                        var sG = sourceData[pos + 1];
                        var sB = sourceData[pos + 2];
                        var sA = sourceData[pos + 3];

                        output[outPos]     = (byte)sR;
                        output[outPos + 1] = (byte)sG;
                        output[outPos + 2] = (byte)sB;
                        pos    += 4;
                        outPos += 3;
                    }
                }
                result = true;
                break;

            case TextureFormat.RGBA32:
                output = sourceData;
                result = true;
                break;

            case TextureFormat.ARGB32:
                pos    = 0;
                outPos = 0;
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        var fA = sourceData[pos];
                        var fR = sourceData[pos + 1];
                        var fG = sourceData[pos + 2];
                        var fB = sourceData[pos + 3];

                        output[outPos]     = fR;
                        output[outPos + 1] = fG;
                        output[outPos + 2] = fB;
                        output[outPos + 3] = fA;

                        pos    += 4;
                        outPos += 4;
                    }
                }

                result = true;
                break;

            case TextureFormat.ATC_RGBA8:
                output = ATICompressor.Compress(sourceData, width, height, ATICompressor.CompressionFormat.AtcRgbaExplicitAlpha);
                break;

            case TextureFormat.ATC_RGB4:
                output = ATICompressor.Compress(sourceData, width, height, ATICompressor.CompressionFormat.AtcRgb);
                break;

            case TextureFormat.ETC2_RGBA8:
                output = ATICompressor.Compress(sourceData, width, height, ATICompressor.CompressionFormat.Etc2Rgba);
                break;

            case TextureFormat.ETC_RGB4:
                output = ATICompressor.Compress(sourceData, width, height, ATICompressor.CompressionFormat.Etc1);
                break;

            case TextureFormat.DXT5:
                using (DxtCompressor compressor = new DxtCompressor())
                {
                    result = compressor.Compress(sourceData, width, height, Nvidia.TextureTools.Format.DXT5, out output);
                }

                break;

            case TextureFormat.DXT1:
                using (DxtCompressor compressor = new DxtCompressor())
                {
                    result = compressor.Compress(sourceData, width, height, Nvidia.TextureTools.Format.DXT1, out output);
                }
                break;

            case TextureFormat.ASTC_RGBA_4x4:
                Console.WriteLine("compressing astc 4x4");
                astcencWrapper.EncodeASTC(sourceData, width, height, 4, 4, out output);
                break;

            case TextureFormat.ASTC_RGB_4x4:
                Console.WriteLine("compressing astc 4x4");
                astcencWrapper.EncodeASTC(sourceData, width, height, 4, 4, out output);
                break;

            default:
                result = false;
                break;
            }

            return(result);
        }
        protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
        {
            SurfaceFormat sourceFormat;

            if (!sourceBitmap.TryGetFormat(out sourceFormat))
            {
                return(false);
            }

            SurfaceFormat format;

            TryGetFormat(out format);

            // A shortcut for copying the entire bitmap to another bitmap of the same type and format
            if (format == sourceFormat && (sourceRegion == new Rectangle(0, 0, Width, Height)) && sourceRegion == destinationRegion)
            {
                SetPixelData(sourceBitmap.GetPixelData());
                return(true);
            }

            // Destination region copy is not yet supported
            if (destinationRegion != new Rectangle(0, 0, Width, Height))
            {
                return(false);
            }

            // If the source is not Vector4 or requires resizing, send it through BitmapContent.Copy
            if (!(sourceBitmap is PixelBitmapContent <Vector4>) || sourceRegion.Width != destinationRegion.Width || sourceRegion.Height != destinationRegion.Height)
            {
                try
                {
                    BitmapContent.Copy(sourceBitmap, sourceRegion, this, destinationRegion);
                    return(true);
                }
                catch (InvalidOperationException)
                {
                    return(false);
                }
            }

            // Convert to full colour 32-bit format. Floating point would be preferred for processing, but it appears the ATICompressor does not support this
            var colorBitmap = new PixelBitmapContent <Color>(sourceRegion.Width, sourceRegion.Height);

            BitmapContent.Copy(sourceBitmap, sourceRegion, colorBitmap, new Rectangle(0, 0, colorBitmap.Width, colorBitmap.Height));
            sourceBitmap = colorBitmap;

            ATICompressor.CompressionFormat targetFormat;
            switch (format)
            {
            case SurfaceFormat.RgbaAtcExplicitAlpha:
                targetFormat = ATICompressor.CompressionFormat.AtcRgbaExplicitAlpha;
                break;

            case SurfaceFormat.RgbaAtcInterpolatedAlpha:
                targetFormat = ATICompressor.CompressionFormat.AtcRgbaInterpolatedAlpha;
                break;

            default:
                return(false);
            }

            var sourceData     = sourceBitmap.GetPixelData();
            var compressedData = ATICompressor.Compress(sourceData, Width, Height, targetFormat);

            SetPixelData(compressedData);

            return(true);
        }