protected ClusterFit(ColourSet colours, SquishOptions flags) : base(colours, flags) { // Set the iteration count. this._IterationCount = flags.HasFlag(SquishOptions.ColourIterativeClusterFit) ? MaxIterations : 1; // Initialise the best error. this._BestError = new Vector4(float.MaxValue); // Initialize the metric var perceptual = flags.HasFlag(SquishOptions.ColourMetricPerceptual); if (perceptual) { this._Metric = new Vector4(0.2126f, 0.7152f, 0.0722f, 0.0f); } else { this._Metric = new Vector4(1.0f); } // Get the covariance matrix. var covariance = Sym3x3.ComputeWeightedCovariance(colours.Count, colours.Points, colours.Weights); // Compute the principle component this._Principle = Sym3x3.ComputePrincipledComponent(covariance); }
public static byte[] CompressBlockMasked(byte[] rgba, int mask, SquishOptions flags) { flags = flags.FixFlags(); ColourSet colours = new ColourSet(rgba, mask, flags); if (colours.Count == 1) { // Always do a single colour fit //SingleColourFit fit = new SingleColourFit(ref colours, flags); } else if (flags.HasFlag(SquishOptions.ColourRangeFit) || colours.Count == 0) { // Do a range fit //RangeFit fit = new RangeFit(ref colours, flags, metric); } else { // Default to a cluster fit (could be iterative or not) //ClusterFit fit = new ClusterFit(ref colours, flags, metric); } // Compress alpha separately if needed if (flags.HasFlag(SquishOptions.DXT3)) { //Alpha.CompressAlphaDxt3(rgba, mask, alphaBlock); } else if (flags.HasFlag(SquishOptions.DXT5)) { //Alpha.CompressAlphaDxt5(rgba, mask, alphaBlock); } throw new NotImplementedException(); }
public static byte[] DecompressBlock(byte[] block, int blockOffset, SquishOptions flags) { // Get the block locations var colOff = blockOffset; var alphaOff = blockOffset; if ((flags & (SquishOptions.DXT3 | SquishOptions.DXT5)) != 0) { colOff += 8; } // Decompress colour. var rgba = ColourBlock.DecompressColour(block, colOff, flags.HasFlag(SquishOptions.DXT1)); // Decompress alpha seperately if necessary. if (flags.HasFlag(SquishOptions.DXT3)) { Alpha.DecompressAlphaDxt3(block, alphaOff, rgba, 0); } else if (flags.HasFlag(SquishOptions.DXT5)) { Alpha.DecompressAlphaDxt5(block, alphaOff, rgba, 0); } return rgba; }
public static byte[] DecompressBlock(byte[] block, int blockOffset, SquishOptions flags) { // Get the block locations var colOff = blockOffset; var alphaOff = blockOffset; if ((flags & (SquishOptions.DXT3 | SquishOptions.DXT5)) != 0) { colOff += 8; } // Decompress colour. var rgba = ColourBlock.DecompressColour(block, colOff, flags.HasFlag(SquishOptions.DXT1)); // Decompress alpha seperately if necessary. if (flags.HasFlag(SquishOptions.DXT3)) { Alpha.DecompressAlphaDxt3(block, alphaOff, rgba, 0); } else if (flags.HasFlag(SquishOptions.DXT5)) { Alpha.DecompressAlphaDxt5(block, alphaOff, rgba, 0); } return(rgba); }
public static int GetStorageRequirements(int width, int height, SquishOptions flags) { var blockCount = ((width + 3) / 4) * ((height + 3) / 4); var blockSize = flags.HasFlag(SquishOptions.DXT1) ? 8 : 16; return(blockCount * blockSize); }
public static Image <Rgba32> DecompressToImage(byte[] blocks, int offset, int width, int height, SquishOptions flags) { var result = new Image <Rgba32>(width, height); var bufferOffset = 0; var bytesPerBlock = flags.HasFlag(SquishOptions.DXT1) ? 8 : 16; var blockOffset = offset; // Loop over blocks. for (var y = 0; y < height; y += 4) { for (var x = 0; x < width; x += 4) { // Decompress the block. var targetRgba = DecompressBlock(blocks, blockOffset, flags); // Write the decompressed pixels to the correct image locations. var sourcePixelOffset = 0; for (var py = 0; py < 4; ++py) { for (var px = 0; px < 4; ++px) { // Get the target location. var sx = x + px; var sy = y + py; if (sx < width && sy < height) { var sourceColour = new Rgba32 ( targetRgba[sourcePixelOffset + 0], targetRgba[sourcePixelOffset + 1], targetRgba[sourcePixelOffset + 2], targetRgba[sourcePixelOffset + 3] ); result[sx, sy] = sourceColour; /* * var i = 4 * (sx + (sy * width)); * fullBuffer[bufferOffset + i + 0] = targetRgba[sourcePixelOffset + 2]; * fullBuffer[bufferOffset + i + 1] = targetRgba[sourcePixelOffset + 1]; * fullBuffer[bufferOffset + i + 2] = targetRgba[sourcePixelOffset + 0]; * fullBuffer[bufferOffset + i + 3] = targetRgba[sourcePixelOffset + 3]; */ } sourcePixelOffset += 4; // Skip this pixel as it is outside the image. } } // advance blockOffset += bytesPerBlock; } } return(result); }
public static unsafe Image DecompressToBitmap(byte[] blocks, int offset, int width, int height, SquishOptions flags) { var fullBuffer = new byte[4 * width * height]; var bufferOffset = 0; var bytesPerBlock = flags.HasFlag(SquishOptions.DXT1) ? 8 : 16; var blockOffset = offset; // Loop over blocks. for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { // Decompress the block. var targetRgba = DecompressBlock(blocks, blockOffset, flags); // Write the decompressed pixels to the correct image locations. var sourcePixelOffset = 0; for (int py = 0; py < 4; ++py) { for (int px = 0; px < 4; ++px) { // Get the target location. var sx = x + px; var sy = y + py; if (sx < width && sy < height) { var i = 4 * (sx + (sy * width)); fullBuffer[bufferOffset + i + 0] = targetRgba[sourcePixelOffset + 2]; fullBuffer[bufferOffset + i + 1] = targetRgba[sourcePixelOffset + 1]; fullBuffer[bufferOffset + i + 2] = targetRgba[sourcePixelOffset + 0]; fullBuffer[bufferOffset + i + 3] = targetRgba[sourcePixelOffset + 3]; } sourcePixelOffset += 4; // Skip this pixel as it is outside the image. } } // advance blockOffset += bytesPerBlock; } } Image ret; fixed(byte *p = fullBuffer) { var ptr = (IntPtr)p; var tempImage = new Bitmap(width, height, 4 * width, System.Drawing.Imaging.PixelFormat.Format32bppArgb, ptr); ret = new Bitmap(tempImage); } return(ret); }
public void Compress(ref byte[] block) { if (_Flags.HasFlag(SquishOptions.DXT1)) { Compress3(block); if (!_Colours.IsTransparent) { Compress4(block); } } else { Compress4(block); } }
public static byte[] DecompressImage(byte[] blocks, int offset, int width, int height, SquishOptions flags) { var argb = new byte[4 * width * height]; var bytesPerBlock = flags.HasFlag(SquishOptions.DXT1) ? 8 : 16; var blockOffset = offset; // Loop over blocks. for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { // Decompress the block. var targetRgba = DecompressBlock(blocks, blockOffset, flags); // Write the decompressed pixels to the correct image locations. var sourcePixelOffset = 0; for (int py = 0; py < 4; ++py) { for (int px = 0; px < 4; ++px) { // Get the target location. var sx = x + px; var sy = y + py; if (sx < width && sy < height) { var targetPixelOffset = 4 * ((width * sy) + sx); // Copy the rgba value argb[targetPixelOffset + 0] = targetRgba[sourcePixelOffset + 2]; argb[targetPixelOffset + 1] = targetRgba[sourcePixelOffset + 1]; argb[targetPixelOffset + 2] = targetRgba[sourcePixelOffset + 0]; argb[targetPixelOffset + 3] = targetRgba[sourcePixelOffset + 3]; } sourcePixelOffset += 4; } } // advance blockOffset += bytesPerBlock; } } return(argb); }
public static byte[] DecompressImage(byte[] blocks, int offset, int width, int height, SquishOptions flags) { var argb = new byte[4 * width * height]; var bytesPerBlock = flags.HasFlag(SquishOptions.DXT1) ? 8 : 16; var blockOffset = offset; // Loop over blocks. for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { // Decompress the block. var targetRgba = DecompressBlock(blocks, blockOffset, flags); // Write the decompressed pixels to the correct image locations. var sourcePixelOffset = 0; for (int py = 0; py < 4; ++py) { for (int px = 0; px < 4; ++px) { // Get the target location. var sx = x + px; var sy = y + py; if (sx < width && sy < height) { var targetPixelOffset = 4 * ((width * sy) + sx); // Copy the rgba value argb[targetPixelOffset + 0] = targetRgba[sourcePixelOffset + 2]; argb[targetPixelOffset + 1] = targetRgba[sourcePixelOffset + 1]; argb[targetPixelOffset + 2] = targetRgba[sourcePixelOffset + 0]; argb[targetPixelOffset + 3] = targetRgba[sourcePixelOffset + 3]; } sourcePixelOffset += 4; } } // advance blockOffset += bytesPerBlock; } } return argb; }
public ColourSet(byte[] rgba, int mask, SquishOptions flags) { // Check the compression mode. var isDxt1 = flags.HasFlag(SquishOptions.DXT1); var weightByAlpha = flags.HasFlag(SquishOptions.WeightColourByAlpha); // Create he minimal set. for (int i = 0; i < 16; ++i) { // Check this pixel is enabled. int bit = 1 << i; if ((mask & bit) == 0) { this._Remap[i] = -1; continue; } // Check for transparent pixels when using DXT1. if (isDxt1 && rgba[4 * i + 3] < 128) { this._Remap[i] = -1; this._IsTransparent = true; } // Loop over previous points for a match. for (int j = 0;; ++j) { // Allocate a new point. if (j == i) { // Normalise coordinates to [0,1]. var x = rgba[4 * i] / 255f; var y = rgba[4 * i + 1] / 255f; var z = rgba[4 * i + 2] / 255f; // Ensure there is always a non-zero weight even for zero alpha. var w = (rgba[4 * i + 3] + 1) / 256f; // Add the point. this._Points[this._Count] = new Vector3(x, y, z); this._Weights[this._Count] = w; this._Remap[i] = this._Count; // Advance. ++this._Count; break; } // Check for a match. int oldBit = 1 << j; var match = ((mask & oldBit) != 0) && (rgba[4 * i] == rgba[4 * j]) && (rgba[4 * i + 1] == rgba[4 * j + 1]) && (rgba[4 * i + 3] == rgba[4 * j + 2]) && (rgba[4 * j + 3] >= 128 || !isDxt1); if (match) { // Get index of the match. var index = this._Remap[j]; // Ensure there is always a non-zero weight even for zero alpha. var w = (rgba[4 * i + 3] + 1) / 256f; // Map this point and increase the weight. this._Weights[index] += (weightByAlpha ? w : 1f); this._Remap[i] = index; break; } } } // Square root the weights. for (int i = 0; i < this._Count; ++i) { this._Weights[i] = (float)Math.Sqrt(this._Weights[i]); } }
public static int GetStorageRequirements(int width, int height, SquishOptions flags) { var blockCount = ((width + 3) / 4) * ((height + 3) / 4); var blockSize = flags.HasFlag(SquishOptions.DXT1) ? 8 : 16; return blockCount * blockSize; }
public static unsafe Image DecompressToBitmap(byte[] blocks, int offset, int width, int height, SquishOptions flags) { var fullBuffer = new byte[4 * width * height]; var bufferOffset = 0; var bytesPerBlock = flags.HasFlag(SquishOptions.DXT1) ? 8 : 16; var blockOffset = offset; // Loop over blocks. for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { // Decompress the block. var targetRgba = DecompressBlock(blocks, blockOffset, flags); // Write the decompressed pixels to the correct image locations. var sourcePixelOffset = 0; for (int py = 0; py < 4; ++py) { for (int px = 0; px < 4; ++px) { // Get the target location. var sx = x + px; var sy = y + py; if (sx < width && sy < height) { var i = 4 * (sx + (sy * width)); fullBuffer[bufferOffset + i + 0] = targetRgba[sourcePixelOffset + 2]; fullBuffer[bufferOffset + i + 1] = targetRgba[sourcePixelOffset + 1]; fullBuffer[bufferOffset + i + 2] = targetRgba[sourcePixelOffset + 0]; fullBuffer[bufferOffset + i + 3] = targetRgba[sourcePixelOffset + 3]; } sourcePixelOffset += 4; // Skip this pixel as it is outside the image. } } // advance blockOffset += bytesPerBlock; } } Image ret; fixed (byte* p = fullBuffer) { var ptr = (IntPtr)p; var tempImage = new Bitmap(width, height, 4 * width, System.Drawing.Imaging.PixelFormat.Format32bppArgb, ptr); ret = new Bitmap(tempImage); } return ret; }