protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion) { SurfaceFormat sourceFormat; if (!sourceBitmap.TryGetFormat(out sourceFormat)) { return(false); } // A shortcut for copying the entire bitmap to another bitmap of the same type and format if (SurfaceFormat.RgbEtc1 == 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); } } // Create the texture object in the PVR library var sourceData = sourceBitmap.GetPixelData(); var rgba32F = (PixelFormat)0x2020202061626772; // static const PixelType PVRStandard32PixelType = PixelType('r', 'g', 'b', 'a', 32, 32, 32, 32); using (var pvrTexture = PVRTexture.CreateTexture(sourceData, (uint)sourceBitmap.Width, (uint)sourceBitmap.Height, 1, rgba32F, true, VariableType.Float, ColourSpace.lRGB)) { // Resize the bitmap if needed if ((sourceBitmap.Width != Width) || (sourceBitmap.Height != Height)) { pvrTexture.Resize((uint)Width, (uint)Height, 1, ResizeMode.Cubic); } pvrTexture.Transcode(PixelFormat.ETC1, VariableType.UnsignedByte, ColourSpace.lRGB /*, CompressorQuality.ETCMediumPerceptual, true*/); var texDataSize = pvrTexture.GetTextureDataSize(0); var texData = new byte[texDataSize]; pvrTexture.GetTextureData(texData, texDataSize); SetPixelData(texData); } return(true); }
protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion) { SurfaceFormat sourceFormat; if (!sourceBitmap.TryGetFormat(out sourceFormat)) return false; // A shortcut for copying the entire bitmap to another bitmap of the same type and format if (SurfaceFormat.RgbEtc1 == 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; } } // Create the texture object in the PVR library var sourceData = sourceBitmap.GetPixelData(); var rgba32F = (PixelFormat)0x2020202061626772; // static const PixelType PVRStandard32PixelType = PixelType('r', 'g', 'b', 'a', 32, 32, 32, 32); using (var pvrTexture = PVRTexture.CreateTexture(sourceData, (uint)sourceBitmap.Width, (uint)sourceBitmap.Height, 1, rgba32F, true, VariableType.Float, ColourSpace.lRGB)) { // Resize the bitmap if needed if ((sourceBitmap.Width != Width) || (sourceBitmap.Height != Height)) pvrTexture.Resize((uint)Width, (uint)Height, 1, ResizeMode.Cubic); pvrTexture.Transcode(PixelFormat.ETC1, VariableType.UnsignedByte, ColourSpace.lRGB /*, CompressorQuality.ETCMediumPerceptual, true*/); var texDataSize = pvrTexture.GetTextureDataSize(0); var texData = new byte[texDataSize]; pvrTexture.GetTextureData(texData, texDataSize); SetPixelData(texData); } return true; }
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; }
/// <summary> /// Copies one bitmap into another. /// The destination bitmap can be in any format and size. If the destination is larger or smaller, the source bitmap is scaled accordingly. /// </summary> /// <param name="sourceBitmap">BitmapContent being copied.</param> /// <param name="sourceRegion">Region of sourceBitmap.</param> /// <param name="destinationBitmap">BitmapContent being overwritten.</param> /// <param name="destinationRegion">Region of bitmap to be overwritten.</param> public static void Copy(BitmapContent sourceBitmap, Rectangle sourceRegion, BitmapContent destinationBitmap, Rectangle destinationRegion) { ValidateCopyArguments(sourceBitmap, sourceRegion, destinationBitmap, destinationRegion); SurfaceFormat sourceFormat; if (!sourceBitmap.TryGetFormat(out sourceFormat)) { throw new InvalidOperationException("Could not retrieve surface format of source bitmap"); } SurfaceFormat destinationFormat; if (!destinationBitmap.TryGetFormat(out destinationFormat)) { throw new InvalidOperationException("Could not retrieve surface format of destination bitmap"); } // If the formats are the same and the regions are the full bounds of the bitmaps and they are the same size, do a simpler copy if (sourceFormat == destinationFormat && sourceRegion == destinationRegion && sourceRegion == new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height) && destinationRegion == new Rectangle(0, 0, destinationBitmap.Width, destinationBitmap.Height)) { destinationBitmap.SetPixelData(sourceBitmap.GetPixelData()); return; } // The basic process is // 1. Copy from source bitmap region to a new PixelBitmapContent<Vector4> using sourceBitmap.TryCopyTo() // 2. If source and destination regions are a different size, resize Vector4 version // 3. Copy from Vector4 to destination region using destinationBitmap.TryCopyFrom() // Copy from the source to the intermediate Vector4 format var intermediate = new PixelBitmapContent <Vector4>(sourceRegion.Width, sourceRegion.Height); var intermediateRegion = new Rectangle(0, 0, intermediate.Width, intermediate.Height); if (sourceBitmap.TryCopyTo(intermediate, sourceRegion, intermediateRegion)) { // Resize the intermediate if required if (intermediate.Width != destinationRegion.Width || intermediate.Height != destinationRegion.Height) { intermediate = intermediate.Resize(destinationRegion.Width, destinationRegion.Height) as PixelBitmapContent <Vector4>; } // Copy from the intermediate to the destination if (destinationBitmap.TryCopyFrom(intermediate, new Rectangle(0, 0, intermediate.Width, intermediate.Height), destinationRegion)) { return; } } // If we got here, one of the above steps didn't work throw new InvalidOperationException("Could not copy between " + sourceFormat + " and " + destinationFormat); }
internal static BitmapContent Resize(this BitmapContent bitmap, int newWidth, int newHeight) { BitmapContent src = bitmap; SurfaceFormat format; src.TryGetFormat(out format); if (format != SurfaceFormat.Vector4) { var v4 = new PixelBitmapContent <Vector4>(src.Width, src.Height); BitmapContent.Copy(src, v4); src = v4; } // Convert to FreeImage bitmap var bytes = src.GetPixelData(); var fi = FreeImage.ConvertFromRawBits(bytes, FREE_IMAGE_TYPE.FIT_RGBAF, src.Width, src.Height, SurfaceFormat.Vector4.GetSize() * src.Width, 128, 0, 0, 0, true); // Resize var newfi = FreeImage.Rescale(fi, newWidth, newHeight, FREE_IMAGE_FILTER.FILTER_BICUBIC); FreeImage.UnloadEx(ref fi); // Convert back to PixelBitmapContent<Vector4> src = new PixelBitmapContent <Vector4>(newWidth, newHeight); bytes = new byte[SurfaceFormat.Vector4.GetSize() * newWidth * newHeight]; FreeImage.ConvertToRawBits(bytes, newfi, SurfaceFormat.Vector4.GetSize() * newWidth, 128, 0, 0, 0, true); src.SetPixelData(bytes); FreeImage.UnloadEx(ref newfi); // Convert back to source type if required if (format != SurfaceFormat.Vector4) { var s = (BitmapContent)Activator.CreateInstance(bitmap.GetType(), new object[] { newWidth, newHeight }); BitmapContent.Copy(src, s); src = s; } return(src); }
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; } } //SquishFlags targetFormat = SquishFlags.ColourClusterFit; Format outputFormat = Format.DXT1; switch (format) { case SurfaceFormat.Dxt1: outputFormat = Format.DXT1; break; case SurfaceFormat.Dxt1SRgb: outputFormat = Format.DXT1; break; case SurfaceFormat.Dxt3: outputFormat = Format.DXT3; break; case SurfaceFormat.Dxt3SRgb: outputFormat = Format.DXT3; break; case SurfaceFormat.Dxt5: outputFormat = Format.DXT5; break; case SurfaceFormat.Dxt5SRgb: outputFormat = Format.DXT5; break; default: return false; } // libsquish requires RGBA8888 var colorBitmap = new PixelBitmapContent<Color>(sourceBitmap.Width, sourceBitmap.Height); BitmapContent.Copy(sourceBitmap, colorBitmap); var sourceData = colorBitmap.GetPixelData(); /* var dataSize = Squish.GetStorageRequirements(colorBitmap.Width, colorBitmap.Height, targetFormat); var data = new byte[dataSize]; var metric = new float[] { 1.0f, 1.0f, 1.0f }; Squish.CompressImage(sourceData, colorBitmap.Width, colorBitmap.Height, data, targetFormat, metric); SetPixelData(data); */ var dxtCompressor = new Compressor(); var inputOptions = new InputOptions(); if (outputFormat != Format.DXT1) inputOptions.SetAlphaMode(AlphaMode.Premultiplied); else inputOptions.SetAlphaMode(AlphaMode.None); inputOptions.SetTextureLayout(TextureType.Texture2D, colorBitmap.Width, colorBitmap.Height, 1); // Small hack here. NVTT wants 8bit data in BGRA. Flip the B and R channels // again here. GraphicsUtil.BGRAtoRGBA(sourceData); var dataHandle = GCHandle.Alloc(sourceData, GCHandleType.Pinned); try { var dataPtr = dataHandle.AddrOfPinnedObject(); inputOptions.SetMipmapData(dataPtr, colorBitmap.Width, colorBitmap.Height, 1, 0, 0); inputOptions.SetMipmapGeneration(false); inputOptions.SetGamma(1.0f, 1.0f); var outputOptions = new OutputOptions(); outputOptions.SetOutputHeader(false); var handler = new DxtDataHandler(this); outputOptions.SetOutputHandler(handler.BeginImage, handler.WriteData); var compressionOptions = new CompressionOptions(); compressionOptions.SetFormat(outputFormat); compressionOptions.SetQuality(Quality.Normal); dxtCompressor.Compress(inputOptions, compressionOptions, outputOptions); } finally { dataHandle.Free (); } return true; }
/// <summary> /// Copies one bitmap into another. /// The destination bitmap can be in any format and size. If the destination is larger or smaller, the source bitmap is scaled accordingly. /// </summary> /// <param name="sourceBitmap">BitmapContent being copied.</param> /// <param name="sourceRegion">Region of sourceBitmap.</param> /// <param name="destinationBitmap">BitmapContent being overwritten.</param> /// <param name="destinationRegion">Region of bitmap to be overwritten.</param> public static void Copy(BitmapContent sourceBitmap, Rectangle sourceRegion, BitmapContent destinationBitmap, Rectangle destinationRegion) { ValidateCopyArguments(sourceBitmap, sourceRegion, destinationBitmap, destinationRegion); SurfaceFormat sourceFormat; if (!sourceBitmap.TryGetFormat(out sourceFormat)) throw new InvalidOperationException("Could not retrieve surface format of source bitmap"); SurfaceFormat destinationFormat; if (!destinationBitmap.TryGetFormat(out destinationFormat)) throw new InvalidOperationException("Could not retrieve surface format of destination bitmap"); // If the formats are the same and the regions are the full bounds of the bitmaps and they are the same size, do a simpler copy if (sourceFormat == destinationFormat && sourceRegion == destinationRegion && sourceRegion == new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height) && destinationRegion == new Rectangle(0, 0, destinationBitmap.Width, destinationBitmap.Height)) { destinationBitmap.SetPixelData(sourceBitmap.GetPixelData()); return; } // The basic process is // 1. Copy from source bitmap region to a new PixelBitmapContent<Vector4> using sourceBitmap.TryCopyTo() // 2. If source and destination regions are a different size, resize Vector4 version // 3. Copy from Vector4 to destination region using destinationBitmap.TryCopyFrom() // Copy from the source to the intermediate Vector4 format var intermediate = new PixelBitmapContent<Vector4>(sourceRegion.Width, sourceRegion.Height); var intermediateRegion = new Rectangle(0, 0, intermediate.Width, intermediate.Height); if (sourceBitmap.TryCopyTo(intermediate, sourceRegion, intermediateRegion)) { // Resize the intermediate if required if (intermediate.Width != destinationRegion.Width || intermediate.Height != destinationRegion.Height) intermediate = intermediate.Resize(destinationRegion.Width, destinationRegion.Height) as PixelBitmapContent<Vector4>; // Copy from the intermediate to the destination if (destinationBitmap.TryCopyFrom(intermediate, new Rectangle(0, 0, intermediate.Width, intermediate.Height), destinationRegion)) return; } // If we got here, one of the above steps didn't work throw new InvalidOperationException("Could not copy between " + sourceFormat + " and " + destinationFormat); }
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); } // TODO: Add a XNA unit test to see what it does // my guess is that this is invalid for DXT. // // 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); } } // NVTT wants 8bit data in BGRA format. var colorBitmap = new PixelBitmapContent <Color>(sourceBitmap.Width, sourceBitmap.Height); BitmapContent.Copy(sourceBitmap, colorBitmap); var sourceData = colorBitmap.GetPixelData(); var dataHandle = GCHandle.Alloc(sourceData, GCHandleType.Pinned); AlphaMode alphaMode; Format outputFormat; var alphaDither = false; switch (format) { case SurfaceFormat.Dxt1: case SurfaceFormat.Dxt1SRgb: { bool hasTransparency; PrepareNVTT_DXT1(sourceData, out hasTransparency); outputFormat = hasTransparency ? Format.DXT1a : Format.DXT1; alphaMode = hasTransparency ? AlphaMode.Transparency : AlphaMode.None; alphaDither = true; break; } case SurfaceFormat.Dxt3: case SurfaceFormat.Dxt3SRgb: { PrepareNVTT(sourceData); outputFormat = Format.DXT3; alphaMode = AlphaMode.Transparency; break; } case SurfaceFormat.Dxt5: case SurfaceFormat.Dxt5SRgb: { PrepareNVTT(sourceData); outputFormat = Format.DXT5; alphaMode = AlphaMode.Transparency; break; } default: throw new InvalidOperationException("Invalid DXT surface format!"); } // Do all the calls to the NVTT wrapper within this handler // so we properly clean up if things blow up. try { var dataPtr = dataHandle.AddrOfPinnedObject(); var inputOptions = new InputOptions(); inputOptions.SetTextureLayout(TextureType.Texture2D, colorBitmap.Width, colorBitmap.Height, 1); inputOptions.SetMipmapData(dataPtr, colorBitmap.Width, colorBitmap.Height, 1, 0, 0); inputOptions.SetMipmapGeneration(false); inputOptions.SetGamma(1.0f, 1.0f); inputOptions.SetAlphaMode(alphaMode); var compressionOptions = new CompressionOptions(); compressionOptions.SetFormat(outputFormat); compressionOptions.SetQuality(Quality.Normal); // TODO: This isn't working which keeps us from getting the // same alpha dither behavior on DXT1 as XNA. // // See https://github.com/MonoGame/MonoGame/issues/6259 // //if (alphaDither) //compressionOptions.SetQuantization(false, false, true); var outputOptions = new OutputOptions(); outputOptions.SetOutputHeader(false); outputOptions.SetOutputOptionsOutputHandler(NvttBeginImage, NvttWriteImage, NvttEndImage); var dxtCompressor = new Compressor(); dxtCompressor.Compress(inputOptions, compressionOptions, outputOptions); } finally { dataHandle.Free(); } return(true); }
protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion) { SurfaceFormat sourceFormat; if (!sourceBitmap.TryGetFormat(out sourceFormat)) { return(false); } // 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); } // 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 from a Vector4 format var src = sourceBitmap as PixelBitmapContent <Vector4>; if (default(T) is IPackedVector) { Parallel.For(0, sourceRegion.Height, (y) => { var pixel = default(T); var p = (IPackedVector)pixel; var row = src.GetRow(sourceRegion.Top + y); for (int x = 0; x < sourceRegion.Width; ++x) { p.PackFromVector4(row[sourceRegion.Left + x]); pixel = (T)p; SetPixel(destinationRegion.Left + x, destinationRegion.Top + y, pixel); } }); } else { var converter = new Vector4Converter() as IVector4Converter <T>; // If no converter could be created, converting from this format is not supported if (converter == null) { return(false); } Parallel.For(0, sourceRegion.Height, (y) => { var row = src.GetRow(sourceRegion.Top + y); for (int x = 0; x < sourceRegion.Width; ++x) { SetPixel(destinationRegion.Left + x, destinationRegion.Top + y, converter.FromVector4(row[sourceRegion.Left + x])); } }); } return(true); }
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); }
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); } } //SquishFlags targetFormat = SquishFlags.ColourClusterFit; Format outputFormat = Format.DXT1; switch (format) { case SurfaceFormat.Dxt1: outputFormat = Format.DXT1; break; case SurfaceFormat.Dxt1SRgb: outputFormat = Format.DXT1; break; case SurfaceFormat.Dxt3: outputFormat = Format.DXT3; break; case SurfaceFormat.Dxt3SRgb: outputFormat = Format.DXT3; break; case SurfaceFormat.Dxt5: outputFormat = Format.DXT5; break; case SurfaceFormat.Dxt5SRgb: outputFormat = Format.DXT5; break; default: return(false); } // libsquish requires RGBA8888 var colorBitmap = new PixelBitmapContent <Color>(sourceBitmap.Width, sourceBitmap.Height); BitmapContent.Copy(sourceBitmap, colorBitmap); var sourceData = colorBitmap.GetPixelData(); /* * var dataSize = Squish.GetStorageRequirements(colorBitmap.Width, colorBitmap.Height, targetFormat); * var data = new byte[dataSize]; * var metric = new float[] { 1.0f, 1.0f, 1.0f }; * Squish.CompressImage(sourceData, colorBitmap.Width, colorBitmap.Height, data, targetFormat, metric); * SetPixelData(data); */ var dxtCompressor = new Compressor(); var inputOptions = new InputOptions(); if (outputFormat != Format.DXT1) { inputOptions.SetAlphaMode(AlphaMode.Premultiplied); } else { inputOptions.SetAlphaMode(AlphaMode.None); } inputOptions.SetTextureLayout(TextureType.Texture2D, colorBitmap.Width, colorBitmap.Height, 1); // Small hack here. NVTT wants 8bit data in BGRA. Flip the B and R channels // again here. GraphicsUtil.BGRAtoRGBA(sourceData); var dataHandle = GCHandle.Alloc(sourceData, GCHandleType.Pinned); try { var dataPtr = dataHandle.AddrOfPinnedObject(); inputOptions.SetMipmapData(dataPtr, colorBitmap.Width, colorBitmap.Height, 1, 0, 0); inputOptions.SetMipmapGeneration(false); inputOptions.SetGamma(1.0f, 1.0f); var outputOptions = new OutputOptions(); outputOptions.SetOutputHeader(false); var handler = new DxtDataHandler(this); outputOptions.SetOutputHandler(handler.BeginImage, handler.WriteData); var compressionOptions = new CompressionOptions(); compressionOptions.SetFormat(outputFormat); compressionOptions.SetQuality(Quality.Normal); dxtCompressor.Compress(inputOptions, compressionOptions, outputOptions); } finally { dataHandle.Free(); } return(true); }