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"); }
/// <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); }