Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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();
        }
Esempio n. 3
0
        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;
        }
Esempio n. 4
0
        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();
        }
Esempio n. 5
0
        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);
        }
Esempio n. 6
0
        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);
        }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        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);
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
 public void Compress(ref byte[] block)
 {
     if (_Flags.HasFlag(SquishOptions.DXT1))
     {
         Compress3(block);
         if (!_Colours.IsTransparent)
         {
             Compress4(block);
         }
     }
     else
     {
         Compress4(block);
     }
 }
Esempio n. 11
0
        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);
        }
Esempio n. 12
0
        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;
        }
Esempio n. 13
0
        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]);
            }
        }
Esempio n. 14
0
        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]);
            }
        }
Esempio n. 15
0
 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;
 }
Esempio n. 16
0
        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;
        }