示例#1
0
        public DDS(D3DFormat Format, Bitmap bitmap)
        {
            SquishFlags flags       = SquishFlags.kDxt1;
            bool        bCompressed = true;

            switch (Format)
            {
            case D3DFormat.DXT1:
                flags = SquishFlags.kDxt1;
                break;

            case D3DFormat.DXT3:
                flags = SquishFlags.kDxt3;
                break;

            case D3DFormat.DXT5:
                flags = SquishFlags.kDxt5;
                break;

            default:
                bCompressed = false;
                break;
            }

            format = Format;
            width  = bitmap.Width;
            height = bitmap.Height;

            var mip = new MipMap();

            mip.Width  = width;
            mip.Height = height;

            byte[] data = new byte[mip.Width * mip.Height * 4];

            BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, mip.Width, mip.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

            Marshal.Copy(bmpdata.Scan0, data, 0, bmpdata.Stride * bmpdata.Height);
            bitmap.UnlockBits(bmpdata);

            if (bCompressed)
            {
                for (uint i = 0; i < data.Length - 4; i += 4)
                {
                    byte r = data[i + 0];
                    data[i + 0] = data[i + 2];
                    data[i + 2] = r;
                }

                byte[] dest = new byte[Squish.Squish.GetStorageRequirements(mip.Width, mip.Height, flags | SquishFlags.kColourIterativeClusterFit | SquishFlags.kWeightColourByAlpha)];
                Squish.Squish.CompressImage(data, mip.Width, mip.Height, ref dest, flags | SquishFlags.kColourIterativeClusterFit | SquishFlags.kWeightColourByAlpha);
                mip.Data = dest;
            }
            else
            {
                mip.Data = data;
            }

            mipMaps.Add(mip);
        }
示例#2
0
        public ClusterFit(ColourSet colours, SquishFlags flags)
            : base(colours, flags)
        {
            // set the iteration count
            m_iterationCount = ((m_flags & SquishFlags.kColourIterativeClusterFit) != 0) ? kMaxIterations : 1;

            // initialise the best error
            m_besterror = Vector4.one * float.MaxValue;

            // initialise the metric
            bool perceptual = ((m_flags & SquishFlags.kColourMetricPerceptual) != 0);

            if (perceptual)
            {
                m_metric = new Vector4(0.2126f, 0.7152f, 0.0722f, 0.0f);
            }
            else
            {
                m_metric = Vector4.one;
            }

            // cache some values
            int count = m_colours.GetCount();

            Vector3[] values = m_colours.GetPoints();

            // get the covariance matrix
            Sym3x3 covariance = math.ComputeWeightedCovariance(count, values, m_colours.GetWeights());

            // compute the principle component
            m_principle = math.ComputePrincipleComponent(covariance);
        }
示例#3
0
        public ClusterFit(ColourSet colours, SquishFlags flags, float?metric)
            : base(colours, flags)
        {
            // set the iteration count
            _mIterationCount = (MFlags & SquishFlags.KColourIterativeClusterFit) != 0 ? 8 : 1;

            // initialise the metric (old perceptual = 0.2126f, 0.7152f, 0.0722f)
            if (metric != null)
            {
                //m_metric = Vec4( metric[0], metric[1], metric[2], 1.0f );
            }
            else
            {
                _mMetric = new Vector4(1.0f);
            }

            // initialise the best error
            _mBesterror = new Vector4(float.MaxValue);

            // cache some values
            var count  = MColours.Count;
            var values = MColours.Points;

            // get the covariance matrix
            var covariance = Sym3X3.ComputeWeightedCovariance(count, values, MColours.Weights);

            // compute the principle component
            _mPrinciple = Sym3X3.ComputePrincipleComponent(covariance);
        }
        public ClusterFit(ColourSet colours, SquishFlags flags, float? metric)
            : base(colours, flags)
        {
            // set the iteration count
            m_iterationCount = ((m_flags & SquishFlags.kColourIterativeClusterFit) != 0 ? 8 : 1);

            // initialise the metric (old perceptual = 0.2126f, 0.7152f, 0.0722f)
            if (metric != null)
            {
                //m_metric = Vec4( metric[0], metric[1], metric[2], 1.0f );
            }
            else
            {
                m_metric = new Vector4(1.0f);
            }

            // initialise the best error
            m_besterror = new Vector4(float.MaxValue);

            // cache some values
            int count = m_colours.Count;
            Vector3[] values = m_colours.Points;

            // get the covariance matrix
            Sym3x3 covariance = Sym3x3.ComputeWeightedCovariance(count, values, m_colours.Weights);

            // compute the principle component
            m_principle = Sym3x3.ComputePrincipleComponent(covariance);
        }
示例#5
0
        public Bitmap Decompress(int mipLevel = 0, bool suppressAlpha = false)
        {
            MipMap mip = MipMaps[mipLevel];

            Bitmap      b             = new Bitmap(mip.Width, mip.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            SquishFlags flags         = 0;
            bool        notCompressed = false;

            switch (Format)
            {
            case D3DFormat.DXT1:
                flags = SquishFlags.kDxt1;
                break;

            case D3DFormat.DXT5:
                flags = SquishFlags.kDxt5;
                break;

            case D3DFormat.A8R8G8B8:
                notCompressed = true;
                break;

            default:
                throw new NotImplementedException($"Can't decompress: {Format}");
            }

            byte[] dest = new byte[mip.Width * mip.Height * 4];
            byte[] data = mip.Data;

            if (notCompressed)
            {
                for (uint i = 0; i < data.Length - 4; i += 4)
                {
                    uint colour = (uint)((data[i + 3] << 24) | (data[i + 2] << 16) | (data[i + 1] << 8) | (data[i + 0] << 0));

                    dest[i + 0] = (byte)((colour & PixelFormat.BBitMask) >> 0);
                    dest[i + 1] = (byte)((colour & PixelFormat.GBitMask) >> 8);
                    dest[i + 2] = (byte)((colour & PixelFormat.RBitMask) >> 16);
                    dest[i + 3] = (byte)((colour & PixelFormat.ABitMask) >> 24);
                }
            }
            else
            {
                Squish.Squish.DecompressImage(dest, mip.Width, mip.Height, ref data, flags);

                for (uint i = 0; i < dest.Length - 4; i += 4)
                {
                    byte r = dest[i + 0];
                    dest[i + 0] = dest[i + 2];
                    dest[i + 2] = r;
                }
            }

            BitmapData bmpdata = b.LockBits(new Rectangle(0, 0, mip.Width, mip.Height), ImageLockMode.ReadWrite, (suppressAlpha ? System.Drawing.Imaging.PixelFormat.Format32bppRgb : b.PixelFormat));

            Marshal.Copy(dest, 0, bmpdata.Scan0, dest.Length);
            b.UnlockBits(bmpdata);

            return(b);
        }
示例#6
0
        public ClusterFit(ColourSet colours, SquishFlags flags, float?metric)
            : base(colours, flags)
        {
            // set the iteration count
            m_iterationCount = ((m_flags & SquishFlags.kColourIterativeClusterFit) != 0 ? 8 : 1);

            // initialise the metric (old perceptual = 0.2126f, 0.7152f, 0.0722f)
            if (metric != null)
            {
                //m_metric = Vec4( metric[0], metric[1], metric[2], 1.0f );
            }
            else
            {
                m_metric = new Vector4(1.0f);
            }

            // initialise the best error
            m_besterror = new Vector4(float.MaxValue);

            // cache some values
            int count = m_colours.Count;

            Vector3[] values = m_colours.Points;

            // get the covariance matrix
            Sym3x3 covariance = Sym3x3.ComputeWeightedCovariance(count, values, m_colours.Weights);

            // compute the principle component
            m_principle = Sym3x3.ComputePrincipleComponent(covariance);
        }
示例#7
0
        private static void Decompress(byte[] rgba, ref byte[] block, int offset, SquishFlags flags)
        {
            // fix any bad flags
            flags = FixFlags(flags);

            // get the block locations
            var colourBlock = offset;
            var alphaBlock  = offset;

            if ((flags & (SquishFlags.KDxt3 | SquishFlags.KDxt5)) != 0)
            {
                colourBlock += 8;
            }

            // decompress colour
            ColourBlock.DecompressColour(rgba, ref block, colourBlock, (flags & SquishFlags.KDxt1) != 0);

            // decompress alpha separately if necessary
            if ((flags & SquishFlags.KDxt3) != 0)
            {
                throw new NotImplementedException("Squish.DecompressAlphaDxt3");
                //DecompressAlphaDxt3(rgba, alphaBlock);
            }
            if ((flags & SquishFlags.KDxt5) != 0)
            {
                DecompressAlphaDxt5(rgba, ref block, alphaBlock);
            }
        }
示例#8
0
        public ClusterFit(ColourSet colours, SquishFlags flags)
            : base(colours, flags)
        {
            // set the iteration count
            m_iterationCount = ((m_flags & SquishFlags.ColourIterativeClusterFit) != 0) ? kMaxIterations : 1;

            // initialise the best error
            m_besterror = new Vec4(float.MaxValue);

            // initialise the metric
            bool perceptual = ((m_flags & SquishFlags.ColourMetricPerceptual) != 0);
            if (perceptual)
                m_metric = new Vec4(0.2126f, 0.7152f, 0.0722f, 0.0f);
            else
                m_metric = new Vec4(1.0f);

            // cache some values
            int count = m_colours.GetCount();
            Vec3[] values = m_colours.GetPoints();

            // get the covariance matrix
            Sym3x3 covariance = Sym3x3.ComputeWeightedCovariance(count, values, m_colours.GetWeights());
            // compute the principle component
            m_principle = Sym3x3.ComputePrincipleComponent(covariance);
        }
示例#9
0
        private static SquishFlags fixFlags(SquishFlags flags)
        {
            //
            // grab the flag bits
            //
            SquishFlags method = flags & (SquishFlags.Dxt1 | SquishFlags.Dxt3 | SquishFlags.Dxt5);

            SquishFlags fit = flags & (SquishFlags.ColourIterativeClusterFit | SquishFlags.ColourClusterFit | SquishFlags.ColourRangeFit);

            SquishFlags metric = flags & (SquishFlags.ColourMetricPerceptual | SquishFlags.ColourMetricUniform);

            SquishFlags extra = flags & SquishFlags.WeightColourByAlpha;

            //
            // set defaults
            //
            if (method != SquishFlags.Dxt3 && method != SquishFlags.Dxt5)
            {
                method = SquishFlags.Dxt1;
            }

            if (fit != SquishFlags.ColourRangeFit && fit != SquishFlags.ColourIterativeClusterFit)
            {
                fit = SquishFlags.ColourClusterFit;
            }

            if (metric != SquishFlags.ColourMetricUniform)
            {
                metric = SquishFlags.ColourMetricPerceptual;
            }
            //
            // done
            //
            return(method | fit | metric | extra);
        }
示例#10
0
        private static unsafe void decompress(byte *rgba, byte *block, SquishFlags flags)
        {
            //
            // get the block locations
            //
            byte *colourBlock = block;
            byte *alphaBock   = block;

            if ((flags & (SquishFlags.Dxt3 | SquishFlags.Dxt5)) != 0)
            {
                colourBlock = block + 8;
            }
            //
            // decompress colour
            //
            decompressColour(rgba, colourBlock, (flags & SquishFlags.Dxt1) != 0);
            //
            // decompress alpha separately if necessary
            //
            if ((flags & SquishFlags.Dxt3) != 0)
            {
                decompressAlphaDxt3(rgba, alphaBock);
            }
            else if ((flags & SquishFlags.Dxt5) != 0)
            {
                decompressAlphaDxt5(rgba, alphaBock);
            }
        }
示例#11
0
        public RangeFit( ColourSet  colours, SquishFlags flags )
            : base(colours, flags)
        {
            // initialise the metric
            bool perceptual = ( ( m_flags & SquishFlags.kColourMetricPerceptual ) != 0 );
            if( perceptual )
            m_metric = new Vector3( 0.2126f, 0.7152f, 0.0722f );
            else
            m_metric = Vector3.one;

            // initialise the best error
            m_besterror = float.MaxValue;

            // cache some values
            int  count = m_colours.GetCount();
            Vector3[]  values = m_colours.GetPoints();
            float[]  weights = m_colours.GetWeights();

            // get the covariance matrix
            Sym3x3 covariance = math.ComputeWeightedCovariance( count, values, weights );

            // compute the principle component
            Vector3 principle = math.ComputePrincipleComponent( covariance );

            // get the min and max range as the codebook endpoints
            Vector3 start = Vector3.zero;
            Vector3 end = Vector3.zero;
            if( count > 0 )
            {
            float min, max;

            // compute the range
            start = end = values[0];
            min = max = Vector3.Dot( values[0], principle );
            for( int i = 1; i < count; ++i )
            {
            float val = Vector3.Dot( values[i], principle );
            if( val < min )
            {
                start = values[i];
                min = val;
            }
            else if( val > max )
            {
                end = values[i];
                max = val;
            }
            }
            }

            // clamp the output to [0, 1]
            start = Vector3.Min( Vector3.one,Vector3.Max( Vector3.zero, start ) );
            end = Vector3.Min( Vector3.one, Vector3.Max( Vector3.zero, end ) );

            // clamp to the grid and save

            Vector3  half = Vector3.one*( 0.5f );
            m_start = Vector3.Scale(math.Truncate( Vector3.Scale(grid,start) + half ),gridrcp);
            m_end = Vector3.Scale(math.Truncate( Vector3.Scale(grid,end) + half ),gridrcp);
        }
示例#12
0
        internal static bool WriteTo(Texture2D cacheTexture, string cacheFile, bool compress)
        {
            String directory = Path.GetDirectoryName(cacheFile + ".none");

            if (File.Exists(directory))
            {
                File.Delete(directory);
            }
            Directory.CreateDirectory(directory);
            FileStream imgStream = new FileStream(cacheFile, FileMode.Create, FileAccess.Write);

            imgStream.Position = 0;
            //byte[] png = cacheTexture.EncodeToPNG();
            byte[]        img         = cacheTexture.bytes(0);
            SquishFlags   compression = SquishFlags.kDxt5;
            TextureFormat format      = TextureFormat.DXT5;

            bool hasAlpha = texHasAlpha(img);

            if (!hasAlpha)
            {
                compression = SquishFlags.kDxt1;
                format      = TextureFormat.DXT1;
            }

            for (int i = 0; i < cacheTexture.mipmapCount; i++)
            {
                int width  = Math.Max(1, cacheTexture.width >> i);
                int height = Math.Max(1, cacheTexture.height >> i);
                if (compress)
                {
                    if (i != 0)
                    {
                        img = cacheTexture.bytes(i);
                    }
                    int size = squish.GetStorageRequirements(width, height, compression);
                    if (DatabaseLoaderTexture_ATM.UseSquish)
                    {
                        squish.CompressImage(img, width, height, imageBuffer, compression | SquishFlags.kColourIterativeClusterFit | SquishFlags.kWeightColourByAlpha);
                    }
                    else
                    {
                        TextureToolsDXT.GetDXT(cacheTexture, i, imageBuffer, format);
                    }
                    imgStream.Write(imageBuffer, 0, size);
                }
                else
                {
                    img = cacheTexture.bytes(i, hasAlpha);
                    imgStream.Write(img, 0, img.Length);
                }
                if (width == 1 || height == 1)
                {
                    break;
                }
            }
            imgStream.Close();
            return(hasAlpha);
        }
示例#13
0
        private static unsafe void compressMasked(byte *rgba, int mask, byte *block, SquishFlags flags)
        {
            //
            // get the block locations
            //
            byte *colourBlock = block;
            byte *alphaBlock  = block;

            if ((flags & (SquishFlags.Dxt3 | SquishFlags.Dxt5)) != 0)
            {
                colourBlock = block + 8;
            }
            //
            // create the minimal point set
            //
            ColourSet colours = new ColourSet(rgba, mask, flags);

            //
            // check the compression type and compress colour
            //
            if (colours.Count == 1)
            {
                //
                // always do a single colour fit
                //
                SingleColourFit fit = new SingleColourFit(colours, flags);

                fit.Compress(colourBlock);
            }
            else if ((flags & SquishFlags.ColourRangeFit) != 0 || colours.Count == 0)
            {
                //
                // do a range fit
                //
                RangeFit fit = new RangeFit(colours, flags);

                fit.Compress(colourBlock);
            }
            else
            {
                //
                // default to a cluster fit (could be iterative or not)
                //
                ClusterFit fit = new ClusterFit(colours, flags);

                fit.Compress(colourBlock);
            }
            //
            // compress alpha separately if necessary
            //
            if ((flags & SquishFlags.Dxt3) != 0)
            {
                compressAlphaDxt3(rgba, mask, alphaBlock);
            }
            else if ((flags & SquishFlags.Dxt5) != 0)
            {
                compressAlphaDxt5(rgba, mask, alphaBlock);
            }
        }
        public static void CompressImage(byte[] rgba, int width, int height, ref byte[] blocks, SquishFlags flags)
        {
            // fix any bad flags
            flags = FixFlags(flags);

            // initialise the block output
            int targetBlock = 0;
            int bytesPerBlock = ((flags & SquishFlags.kDxt1) != 0) ? 8 : 16;

            // loop over blocks
            for (int y = 0; y < height; y += 4)
            {
                for (int x = 0; x < width; x += 4)
                {
                    // build the 4x4 block of pixels
                    byte[] sourceRgba = new byte[16 * 4];
                    byte targetPixel = 0;
                    int mask = 0;

                    for (int py = 0; py < 4; ++py)
                    {
                        for (int px = 0; px < 4; ++px)
                        {
                            // get the source pixel in the image
                            int sx = x + px;
                            int sy = y + py;

                            // enable if we're in the image
                            if (sx < width && sy < height)
                            {
                                // copy the rgba value
                                for (int i = 0; i < 4; ++i)
                                {
                                    sourceRgba[targetPixel] = rgba[i + 4 * (width * sy + sx)];
                                    targetPixel++;
                                }

                                // enable this pixel
                                mask |= (1 << (4 * py + px));
                            }
                            else
                            {
                                // skip this pixel as its outside the image
                                targetPixel += 4;
                            }
                        }
                    }

                    // compress it into the output
                    CompressMasked(sourceRgba, mask, ref blocks, targetBlock, flags, null);

                    // advance
                    targetBlock += bytesPerBlock;
                }
            }
        }
示例#15
0
        public static int GetStorageRequirements(int width, int height, SquishFlags flags)
        {
            // fix any bad flags
            flags = FixFlags(flags);

            // compute the storage requirements
            var blockcount = (width + 3) / 4 * ((height + 3) / 4);
            var blocksize  = (flags & SquishFlags.KDxt1) != 0 ? 8 : 16;

            return(blockcount * blocksize);
        }
示例#16
0
        /// <summary>
        /// Decompresses a 4x4 block of pixels.
        /// </summary>
        /// <param name="block">The compressed DXT block.</param>
        /// <param name="width">The width of the source image.</param>
        /// <param name="height">The height of the source image.</param>
        /// <param name="flags">Compression flags.</param>
        /// <returns>Byte array containing the 16 decompressed pixels.</returns>
        /// <remarks>The decompressed pixels will be written as a contiguous array of 16 rgba
        /// values, with each component as 1 byte each. In memory this is:
        /// <code>{ r1, g1, b1, a1, .... , r16, g16, b16, a16 }</code>
        /// The <paramref name="flags"/> parameter should specify either <c>kDxt1</c>, <c>kDxt3</c> or <c>kDxt5</c> compression,
        /// however, DXT1 will be used by default if none is specified. All other flags are ignored.</remarks>
        public static byte[] Decompress(byte[] block, SquishFlags flags)
        {
            // Allocate room for decompressed output
            byte[] pixelOutput = new byte[16];

            // Invoke squish::Decompress() with the required parameters
            SquishDecompress(pixelOutput, block, flags);

            // Return our pixel data to caller..
            return(pixelOutput);
        }
示例#17
0
        /// <summary>
        /// Decompresses an image in memory.
        /// </summary>
        /// <param name="blocks">The compressed DXT blocks.</param>
        /// <param name="width">The width of the source image.</param>
        /// <param name="height">The height of the source image.</param>
        /// <param name="flags">Compression flags.</param>
        /// <returns>Byte array containing the decompressed pixels.</returns>
        /// <remarks>The decompressed pixels will be written as a contiguous array of width*height
        /// 16 rgba values, with each component as 1 byte each. In memory this is:
        /// <code>{ r1, g1, b1, a1, .... , rn, gn, bn, an } for n = width*height</code>
        /// The <paramref name="flags"/> parameter should specify either <c>kDxt1</c>, <c>kDxt3</c> or <c>kDxt5</c> compression,
        /// however, DXT1 will be used by default if none is specified. All other flags are ignored.</remarks>
        public static byte[] DecompressImage(byte[] blocks, int width, int height, SquishFlags flags)
        {
            // Allocate room for decompressed output
            byte[] pixelOutput = new byte[width * height * 4];

            // Invoke squish::DecompressImage() with the required parameters
            SquishDecompressImage(pixelOutput, width, height, blocks, flags);

            // Return our pixel data to caller..
            return(pixelOutput);
        }
示例#18
0
        public SingleColourFit(ColourSet colours, SquishFlags flags)
            : base(colours, flags)
        {
            // grab the single colour
            Vector3[] values = m_colours.Points;
            m_colour[0] = (byte)ColourBlock.FloatToInt(255.0f * values[0].X, 255);
            m_colour[1] = (byte)ColourBlock.FloatToInt(255.0f * values[0].Y, 255);
            m_colour[2] = (byte)ColourBlock.FloatToInt(255.0f * values[0].Z, 255);

            // initialise the best error
            m_besterror = int.MaxValue;
        }
示例#19
0
 /// <summary>
 /// Compresses a 4x4 block of pixels.
 /// </summary>
 /// <param name="rgba">The rgba values of the 16 source pixels.</param>
 /// <param name="flags">Compression flags.</param>
 /// <returns>Return the Compressed Block Data.</returns>
 public static byte[] Compress(byte[] rgba, SquishFlags flags)
 {
     int bytesPerBlock = ((flags & SquishFlags.Dxt1) != 0) ? 8 : 16;
     byte[] output = new byte[bytesPerBlock];
     unsafe
     {
         fixed (byte* lpIn = rgba, lpOut = output)
         {
             Compress(lpIn, lpOut, flags);
         }
     }
     return output;
 }
示例#20
0
        /// <summary>
        /// Compresses a 4x4 block of pixels.
        /// </summary>
        /// <param name="pixelInput">The rgba values of the 16 source pixels.</param>
        /// <param name="flags">Compression flags.</param>
        /// <param name="metric">An optional perceptual metric.</param>
        /// <returns>Byte array containing the compressed DXT block.</returns>
        /// <remarks>
        /// <para>The source pixels should be presented as a contiguous array of 16 rgba
        /// values, with each component as 1 byte each. In memory this should be:
        /// rgba values, with each component as 1 byte each. In memory this should be:
        /// <c>{ r1, g1, b1, a1, .... , rn, gn, bn, an }</c> for n = width*height
        /// </para>
        /// <para>
        /// The <paramref name="flags"/> parameter should specify either <c>kDxt1</c>, <c>kDxt3</c> or <c>kDxt5</c> compression,
        /// however, DXT1 will be used by default if none is specified. When using DXT1
        /// compression, 8 bytes of storage are required for each compressed DXT block.
        /// DXT3 and DXT5 compression require 16 bytes of storage per block.
        /// </para>
        /// <para>
        /// The <paramref name="flags"/> parameter can also specify a preferred colour compressor to use
        /// when fitting the RGB components of the data. Possible colour compressors
        /// are: <c>kColourClusterFit</c> (the default), <c>kColourRangeFit</c> (very fast, low
        /// quality) or <c>kColourIterativeClusterFit</c> (slowest, best quality).
        /// </para>
        /// <para>
        /// When using <c>kColourClusterFit</c> or <c>kColourIterativeClusterFit</c>, an additional
        /// flag can be specified to weight the importance of each pixel by its alpha
        /// value. For images that are rendered using alpha blending, this can
        /// significantly increase the perceived quality.</para>
        /// <para>
        /// The <paramref name="metric"/> parameter can be used to weight the relative importance of each
        /// colour channel, or pass NULL to use the default uniform weight of
        /// <c>{ 1.0f, 1.0f, 1.0f }</c>. This replaces the previous flag-based control that
        /// allowed either uniform or "perceptual" weights with the fixed values
        /// <c>{ 0.2126f, 0.7152f, 0.0722f }</c>. If non-NULL, the metric should point to a
        /// contiguous array of 3 floats.
        /// </para>
        /// </remarks>
        public static byte[] Compress(byte[] pixelInput, SquishFlags flags, float[] metric = null)
        {
            if (metric != null && metric.Length != 3)
            {
                throw new ArgumentException("Non-null metric must reference an array of three floats.");
            }

            byte[] block = new byte[(flags & SquishFlags.kDxt1) != 0 ? 8 : 16];

            SquishCompress(pixelInput, block, flags, metric);

            return(block);
        }
        private static unsafe void CompressImageBlockLine(int width, int height, SquishFlags flags, int y, byte *prgba, byte *targetBlockPtr, int bytesPerBlock)
        {
            byte *targetBlock = targetBlockPtr;

            for (int x = 0; x < width; x += 4)
            {
                // build the 4x4 block of pixels
                byte[] sourceRgba = new byte[16 * 4];
                fixed(byte *psourceRgba = sourceRgba)
                {
                    byte *targetPixel = psourceRgba;
                    int   mask        = 0;

                    for (int py = 0; py < 4; ++py)
                    {
                        for (int px = 0; px < 4; ++px)
                        {
                            // get the source pixel in the image
                            int sx = x + px;
                            int sy = y + py;

                            // enable if we're in the image
                            if (sx < width && sy < height)
                            {
                                // copy the rgba value
                                byte *sourcePixel = prgba + 4 * (width * sy + sx);
                                for (int i = 0; i < 4; ++i)
                                {
                                    *targetPixel++ = *sourcePixel++;
                                }

                                // enable this pixel
                                mask |= (1 << (4 * py + px));
                            }
                            else
                            {
                                // skip this pixel as its outside the image
                                targetPixel += 4;
                            }
                        }
                    }

                    // compress it into the output
                    CompressMasked(sourceRgba, mask, targetBlock, flags);
                }

                // advance
                targetBlock += bytesPerBlock;
            }
        }
示例#22
0
    public SingleColourFit(ColourSet colours, SquishFlags flags) : base(colours, flags) {
      //
      // grab the single colour
      //
      Vec3[] values = colours.Points;

      colour[0] = (byte)ColourBlock.FloatToInt(255.0f * values[0].X, 255);
      colour[1] = (byte)ColourBlock.FloatToInt(255.0f * values[0].Y, 255);
      colour[2] = (byte)ColourBlock.FloatToInt(255.0f * values[0].Z, 255);
      //
      // initialise the best error
      //
      bestError = Int32.MaxValue;
    }
示例#23
0
        /// <summary>
        /// Compress a 4x4 pixel block using the parameters specified in <paramref name="flags"/>. The <paramref name="mask"/> parameter is a used as
        /// a bit mask to specifify what pixels are valid for compression, corresponding the lowest bit to the first pixel.
        /// </summary>
        /// <param name="rgba">Source RGBA block.</param>
        /// <param name="mask">Pixel bit mask.</param>
        /// <param name="flags">Compression flags.</param>
        /// <returns>Output DXT compressed block.</returns>
        public static byte[] CompressMasked(byte[] rgba, int mask, SquishFlags flags)
        {
            byte[] compressedData = new byte[GetStorageRequirements(4, 4, flags)];

            GCHandle pinnedData = GCHandle.Alloc(compressedData, GCHandleType.Pinned);
            GCHandle pinnedRgba = GCHandle.Alloc(rgba, GCHandleType.Pinned);

            CompressMaskedFunction(pinnedRgba.AddrOfPinnedObject(), mask, pinnedData.AddrOfPinnedObject(), (int)flags);

            pinnedRgba.Free();
            pinnedData.Free();

            return(compressedData);
        }
示例#24
0
        /// <summary>
        /// Decompresses a 4x4 pixel block using the parameters specified in <paramref name="flags"/>.
        /// </summary>
        /// <param name="block">Source DXT block.</param>
        /// <param name="flags">Decompression flags.</param>
        /// <returns>Output RGBA decompressed block.</returns>
        public static byte[] Decompress(byte[] block, SquishFlags flags)
        {
            byte[] decompressedData = new byte[4 * 4 * 4];

            GCHandle pinnedData  = GCHandle.Alloc(decompressedData, GCHandleType.Pinned);
            GCHandle pinnedBlock = GCHandle.Alloc(block, GCHandleType.Pinned);

            DecompressFunction(pinnedData.AddrOfPinnedObject(), pinnedBlock.AddrOfPinnedObject(), (int)flags);

            pinnedBlock.Free();
            pinnedData.Free();

            return(decompressedData);
        }
示例#25
0
        /// <summary>
        /// Compresses an image using the parameters specified in <paramref name="flags"/>.
        /// </summary>
        /// <param name="rgba">Source RGBA image.</param>
        /// <param name="width">Width of the image.</param>
        /// <param name="height">Height of the image.</param>
        /// <param name="flags">Compression flags.</param>
        /// <returns>Output DXT compressed image.</returns>
        public static byte[] CompressImage(byte[] rgba, int width, int height, SquishFlags flags)
        {
            byte[] compressedData = new byte[GetStorageRequirements(width, height, flags)];

            GCHandle pinnedData = GCHandle.Alloc(compressedData, GCHandleType.Pinned);
            GCHandle pinnedRgba = GCHandle.Alloc(rgba, GCHandleType.Pinned);

            CompressImageFunction(pinnedRgba.AddrOfPinnedObject(), width, height, pinnedData.AddrOfPinnedObject(), (int)flags);

            pinnedRgba.Free();
            pinnedData.Free();

            return(compressedData);
        }
示例#26
0
        /// <summary>
        /// Decompresses an image using the parameters specified in <paramref name="flags"/>.
        /// </summary>
        /// <param name="blocks">Source DXT compressed image.</param>
        /// <param name="width">Width of the image.</param>
        /// <param name="height">Height of the image.</param>
        /// <param name="flags">Decompression flags.</param>
        /// <returns>Output RGBA decompressed image.</returns>
        public static byte[] DecompressImage(byte[] blocks, int width, int height, SquishFlags flags)
        {
            byte[] decompressedData = new byte[width * height * 4];

            GCHandle pinnedData   = GCHandle.Alloc(decompressedData, GCHandleType.Pinned);
            GCHandle pinnedBlocks = GCHandle.Alloc(blocks, GCHandleType.Pinned);

            DecompressImageFunction(pinnedData.AddrOfPinnedObject(), width, height, pinnedBlocks.AddrOfPinnedObject(), (int)flags);

            pinnedBlocks.Free();
            pinnedData.Free();

            return(decompressedData);
        }
示例#27
0
        public SingleColourFit(ColourSet colours, SquishFlags flags) : base(colours, flags)
        {
            //
            // grab the single colour
            //
            Vec3[] values = colours.Points;

            colour[0] = (byte)ColourBlock.FloatToInt(255.0f * values[0].X, 255);
            colour[1] = (byte)ColourBlock.FloatToInt(255.0f * values[0].Y, 255);
            colour[2] = (byte)ColourBlock.FloatToInt(255.0f * values[0].Z, 255);
            //
            // initialise the best error
            //
            bestError = Int32.MaxValue;
        }
示例#28
0
 private static unsafe void SquishDecompress(byte[] rgba, byte[] block, SquishFlags flags)
 {
     fixed(byte *pRGBA = rgba)
     fixed(byte *pBlock = block)
     {
         if (Is64Bit())
         {
             SquishInterface_64.SquishDecompress(pRGBA, pBlock, (int)flags);
         }
         else
         {
             SquishInterface_32.SquishDecompress(pRGBA, pBlock, (int)flags);
         }
     }
 }
示例#29
0
        /// <summary>
        /// Compresses an image in memory.
        /// </summary>
        /// <param name="pixelInput">The pixels of the source.</param>
        /// <param name="width">The width of the source image.</param>
        /// <param name="height">The height of the source image.</param>
        /// <param name="flags">Compression flags.</param>
        /// <param name="metric">An optional perceptual metric.</param>
        /// <returns>Byte array containing the compressed output.</returns>
        /// <remarks>
        /// <para>
        /// The source pixels should be presented as a contiguous array of width*height
        /// rgba values, with each component as 1 byte each. In memory this should be:
        /// <c>{ r1, g1, b1, a1, .... , rn, gn, bn, an }</c> for n = width*height
        /// </para>
        /// <para>
        /// The <paramref name="flags"/> parameter should specify either <c>kDxt1</c>, <c>kDxt3</c> or <c>kDxt5</c> compression,
        /// however, DXT1 will be used by default if none is specified. When using DXT1
        /// compression, 8 bytes of storage are required for each compressed DXT block.
        /// DXT3 and DXT5 compression require 16 bytes of storage per block.
        /// </para>
        /// <para>
        /// The <paramref name="flags"/> parameter can also specify a preferred colour compressor to use
        /// when fitting the RGB components of the data. Possible colour compressors
        /// are: <c>kColourClusterFit</c> (the default), <c>kColourRangeFit</c> (very fast, low
        /// quality) or <c>kColourIterativeClusterFit</c> (slowest, best quality).
        /// </para>
        /// <para>
        /// When using <c>kColourClusterFit</c> or <c>kColourIterativeClusterFit</c>, an additional
        /// flag can be specified to weight the importance of each pixel by its alpha
        /// value. For images that are rendered using alpha blending, this can
        /// significantly increase the perceived quality.</para>
        /// <para>
        /// The <paramref name="metric"/> parameter can be used to weight the relative importance of each
        /// colour channel, or pass NULL to use the default uniform weight of
        /// <c>{ 1.0f, 1.0f, 1.0f }</c>. This replaces the previous flag-based control that
        /// allowed either uniform or "perceptual" weights with the fixed values
        /// <c>{ 0.2126f, 0.7152f, 0.0722f }</c>. If non-NULL, the metric should point to a
        /// contiguous array of 3 floats.
        /// </para>
        /// </remarks>
        public static byte[] CompressImage(byte[] pixelInput, int width, int height, SquishFlags flags, float[] metric = null)
        {
            if (metric != null && metric.Length != 3)
            {
                throw new ArgumentException("Non-null metric must reference an array of three floats.");
            }

            //int storageRequirements = GetStorageRequirements(width, height, flags);
            byte[] blocks = new byte[((width + 3) >> ((flags & DdsSquish.SquishFlags.kDxt1) == 0 ? 2 : 3)) * 4 * height];

            // Invoke squish::CompressImage() with the required parameters
            SquishCompressImage(pixelInput, width, height, blocks, flags, metric);

            return(blocks);
        }
        static unsafe void CompressMasked(byte[] rgba, int mask, byte *pBlock, SquishFlags flags)
        {
            // fix any bad flags
            flags = FixFlags(flags);


            // get the block locations
            byte *colourBlock = pBlock;
            byte *alphaBock   = pBlock;

            if ((flags & (SquishFlags.kDxt3 | SquishFlags.kDxt5)) != 0)
            {
                colourBlock = pBlock + 8;
            }

            // create the minimal point set
            ColourSet colours = new ColourSet(rgba, mask, flags);

            // check the compression type and compress colour
            if (colours.GetCount() == 1)
            {
                // always do a single colour fit
                SingleColourFit fit = new SingleColourFit(colours, flags);
                fit.Compress(colourBlock);
            }
            else if ((flags & SquishFlags.kColourRangeFit) != 0 || colours.GetCount() == 0)
            {
                // do a range fit
                RangeFit fit = new RangeFit(colours, flags);
                fit.Compress(colourBlock);
            }
            else
            {
                // default to a cluster fit (could be iterative or not)
                ClusterFit fit = new ClusterFit(colours, flags);
                fit.Compress(colourBlock);
            }

            // compress alpha separately if necessary
            if ((flags & SquishFlags.kDxt3) != 0)
            {
                alpha.CompressAlphaDxt3(rgba, mask, alphaBock);
            }
            else if ((flags & SquishFlags.kDxt5) != 0)
            {
                alpha.CompressAlphaDxt5(rgba, mask, alphaBock);
            }
        }
示例#31
0
 private static unsafe void SquishCompress(byte[] rgba, byte[] block, SquishFlags flags, float[] metric)
 {
     fixed(byte *_rgba = rgba)
     fixed(byte *_block   = block)
     fixed(float *_metric = metric)
     {
         if (Is64Bit())
         {
             SquishInterface_64.SquishCompress(_rgba, _block, (int)flags, _metric);
         }
         else
         {
             SquishInterface_32.SquishCompress(_rgba, _block, (int)flags, _metric);
         }
     }
 }
 public CompressImageBlockLineArgs(
     int width,
     int height,
     SquishFlags flags,
     int y,
     byte *prgba,
     byte *targetBlock,
     int bytesPerBlock,
     ManualResetEvent doneEvent)
 {
     this.width         = width;
     this.height        = height;
     this.flags         = flags;
     this.y             = y;
     this.prgba         = prgba;
     this.targetBlock   = targetBlock;
     this.bytesPerBlock = bytesPerBlock;
     this.doneEvent     = doneEvent;
 }
示例#33
0
        private static SquishFlags FixFlags(SquishFlags flags)
        {
            // grab the flag bits
            var method = flags & (SquishFlags.KDxt1 | SquishFlags.KDxt3 | SquishFlags.KDxt5);
            var fit    = flags & (SquishFlags.KColourIterativeClusterFit | SquishFlags.KColourClusterFit | SquishFlags.KColourRangeFit);
            var extra  = flags & SquishFlags.KWeightColourByAlpha;

            // set defaults
            if (method != SquishFlags.KDxt3 && method != SquishFlags.KDxt5)
            {
                method = SquishFlags.KDxt1;
            }
            if (fit != SquishFlags.KColourRangeFit && fit != SquishFlags.KColourIterativeClusterFit)
            {
                fit = SquishFlags.KColourClusterFit;
            }

            // done
            return(method | fit | extra);
        }
示例#34
0
        public static unsafe void CompressImage(byte[] rgba, int width, int height, byte[] blocks, SquishFlags flags, bool waitOnDone)
        {
            // fix any bad flags
            flags = FixFlags(flags);

            // holds the handles to know which thread are free.
            // No more than 50 or Mono commplains.
            // On my machine Environment.ProcessorCount give me a nice 98% CPU
            ManualResetEvent[] doneEvents = new ManualResetEvent[Environment.ProcessorCount];
            for (int i = 0; i < doneEvents.Length; i++)
            {
                doneEvents[i] = new ManualResetEvent(true);
            }

            // initialise the block output
            fixed (byte* pblocks = blocks, prgba = rgba)
            {
                int bytesPerBlock = ((flags & SquishFlags.kDxt1) != 0) ? 8 : 16;
                byte* targetBlock = pblocks;

                // loop over blocks
                for (int y = 0; y < height; y += 4)
                {
                    int threadIdx = GetFreeThreadIdx(doneEvents);
                    doneEvents[threadIdx] = new ManualResetEvent(false);

                    CompressImageBlockLineArgs args = new CompressImageBlockLineArgs(width, height, flags, y, prgba, targetBlock, bytesPerBlock, doneEvents[threadIdx]);
                    targetBlock += bytesPerBlock * ((width >> 2) + ((width & 0x3) != 0 ? 1 : 0));

                    // To debug un comment this line and comment the next one
                    // Threads catch the exceptions (add a try catch ? )
                    //CompressImageBlockLineThread(args);
                    if (waitOnDone && y > (4*Environment.ProcessorCount))
                    {
                        WaitHandle.WaitAny(doneEvents);
                    }
                    ThreadPool.QueueUserWorkItem(CompressImageBlockLineThread, args);
                }
                WaitHandle.WaitAll(doneEvents);
            }
        }
示例#35
0
 /// <summary>
 /// Compresses a 4x4 block of pixels in BCn format.
 /// </summary>
 /// <param name="rgba">The rgba values of the 16 source pixels.</param>
 /// <param name="mask">The valid pixel mask.</param>
 /// <param name="block">Storage for the compressed BCn block.</param>
 /// <param name="flags">Compression flags.</param>
 public static unsafe void CompressMaskedBC(byte* rgba, int mask, byte* block, SquishFlags flags)
 {
     if ((flags & SquishFlags.BC1) != 0)
     {
         SquishFlags cflags = flags;
         cflags = cflags & ~SquishFlags.BC1;
         cflags |= SquishFlags.Dxt1;
         CompressMasked(rgba, mask, block, cflags);
     }
     else if ((flags & SquishFlags.BC2) != 0)
     {
         SquishFlags cflags = flags;
         cflags = cflags & ~SquishFlags.BC2;
         cflags |= SquishFlags.Dxt3;
         CompressMasked(rgba, mask, block, cflags);
     }
     else if ((flags & SquishFlags.BC3) != 0)
     {
         SquishFlags cflags = flags;
         cflags = cflags & ~SquishFlags.BC3;
         cflags |= SquishFlags.Dxt5;
         CompressMasked(rgba, mask, block, cflags);
     }
     else if ((flags & SquishFlags.BC4) != 0)
     {
         AlphaBlock.CompressAlphaDxt5(rgba, mask, block);
     }
     else if ((flags & SquishFlags.BC5) != 0)
     {
         byte* xBlock = rgba;
         byte* yBlock = rgba;
         ColourBlock.SplatX(xBlock);
         ColourBlock.SplatY(yBlock);
         byte* outBlockX = block;
         byte* outBlockY = block + 8;
         AlphaBlock.CompressAlphaDxt5(xBlock, mask, outBlockX);
         AlphaBlock.CompressAlphaDxt5(yBlock, mask, outBlockY);
     }
 }
示例#36
0
 /// <summary>
 /// Compresses an image in memory.
 /// </summary>
 /// <param name="rgba">The pixels of the source.</param>
 /// <param name="width">The width of the source image.</param>
 /// <param name="height">The height of the source image.</param>
 /// <param name="flags">Compression flags.</param>
 /// <returns>Return the Compressed Image Data.</returns>
 public static byte[] CompressImage(byte[] rgba, int width, int height, SquishFlags flags)
 {
     byte[] output = new byte[GetStorageRequirements(width, height, flags)];
     unsafe
     {
         fixed (byte* lpIn = rgba, lpOut = output)
         {
             CompressImage(lpIn, width, height, lpOut, flags);
         }
     }
     return output;
 }
示例#37
0
        /// <summary>
        /// Compresses an image in memory.
        /// </summary>
        /// <param name="rgba">The pixels of the source.</param>
        /// <param name="width">The width of the source image.</param>
        /// <param name="height">The height of the source image.</param>
        /// <param name="blocks">Storage for the compressed output.</param>
        /// <param name="flags">Compression flags.</param>
        public static unsafe void CompressImage(byte* rgba, int width, int height, byte* blocks, SquishFlags flags)
        {
            bool b_cancel = false;

            // fix any bad flags
            flags = FixFlags(flags);

            // initialise the block output
            byte* targetBlock = blocks;
            int bytesPerBlock = BytesPerBlock(flags);
            int current = 0, blocksCount = GetBlocksCount(width, height);
            // loop over blocks
            for (int y = 0; y < height; y += 4)
            {
                for (int x = 0; x < width; x += 4)
                {
                    // build the 4x4 block of pixels
                    byte[] sourceRgba = new byte[16 * 4];
                    fixed (byte* fixSourceRgba = sourceRgba)
                    {
                        byte* targetPixel = fixSourceRgba;
                        //byte* targetPixel = sourceRgba;
                        int mask = 0;
                        for (int py = 0; py < 4; ++py)
                        {
                            for (int px = 0; px < 4; ++px)
                            {
                                // get the source pixel in the image
                                int sx = x + px;
                                int sy = y + py;

                                // enable if we're in the image
                                if (sx < width && sy < height)
                                {
                                    // copy the rgba value
                                    byte* sourcePixel = rgba + 4 * (width * sy + sx);
                                    for (int i = 0; i < 4; ++i)
                                        *targetPixel++ = *sourcePixel++;

                                    // enable this pixel
                                    mask |= (1 << (4 * py + px));
                                }
                                else
                                {
                                    // skip this pixel as its outside the image
                                    targetPixel += 4;
                                }
                            }
                        }
                        // compress it into the output
                        CompressMasked(fixSourceRgba, mask, targetBlock, flags);
                    }
                    if (BlockAdvance != null)
                    {
                        SharpSquishBlockAdvanceEventArgs e = new SharpSquishBlockAdvanceEventArgs();
                        e.Current = current;
                        e.Blocks = blocksCount;
                        BlockAdvance(e);
                        if (e.Cancel)
                        {
                            b_cancel = true;
                            break;
                        }
                    }
                    // advance
                    targetBlock += bytesPerBlock;
                    current++;
                }
                if (b_cancel)
                    break;
            }
        }
示例#38
0
        private static SquishFlags FixFlags(SquishFlags flags)
        {
            // grab the flag bits
            SquishFlags method = flags & (SquishFlags.Dxt1 | SquishFlags.Dxt3 | SquishFlags.Dxt5 | SquishFlags.BC1 | SquishFlags.BC2 | SquishFlags.BC3 | SquishFlags.BC4 | SquishFlags.BC5);
            SquishFlags fit = flags & (SquishFlags.ColourIterativeClusterFit | SquishFlags.ColourClusterFit | SquishFlags.ColourRangeFit);
            SquishFlags metric = flags & (SquishFlags.ColourMetricPerceptual | SquishFlags.ColourMetricUniform);
            SquishFlags extra = flags & SquishFlags.WeightColourByAlpha;

            // set defaults
            if (method != SquishFlags.Dxt3 && method != SquishFlags.Dxt5 && method != SquishFlags.BC1 && method != SquishFlags.BC2 && method != SquishFlags.BC3 && method != SquishFlags.BC4 && method != SquishFlags.BC5)
                method = SquishFlags.Dxt1;
            if (fit != SquishFlags.ColourRangeFit)
                fit = SquishFlags.ColourClusterFit;
            if (metric != SquishFlags.ColourMetricUniform)
                metric = SquishFlags.ColourMetricPerceptual;

            // done
            return method | fit | metric | extra;
        }
示例#39
0
 public static int BytesPerBlock(SquishFlags flags)
 {
     if ((flags & (SquishFlags.Dxt1 | SquishFlags.BC1 | SquishFlags.BC4)) != 0)
         return 8;
     return 16;
 }
示例#40
0
 private static unsafe void SquishCompressImage(byte[] rgba, int width, int height, byte[] blocks, SquishFlags flags, float[] metric)
 {
     fixed(byte *_rgba = rgba)
     fixed(byte *_blocks  = blocks)
     fixed(float *_metric = metric)
     {
         if (Is64Bit())
         {
             SquishInterface_64.SquishCompressImage(_rgba, width, height, _blocks, (int)flags, _metric);
         }
         else
         {
             SquishInterface_32.SquishCompressImage(_rgba, width, height, _blocks, (int)flags, _metric);
         }
     }
 }
示例#41
0
    private static unsafe void compressMasked(byte *rgba, int mask, byte *block, SquishFlags flags) {
      //
      // get the block locations
      //
      byte *colourBlock = block;
      byte *alphaBlock  = block;

      if ((flags & (SquishFlags.Dxt3 | SquishFlags.Dxt5)) != 0) colourBlock = block + 8;
      //
      // create the minimal point set
      //
      ColourSet colours = new ColourSet(rgba, mask, flags);
      //
      // check the compression type and compress colour
      //
      if (colours.Count == 1) {
        //
        // always do a single colour fit
        //
        SingleColourFit fit = new SingleColourFit(colours, flags);

        fit.Compress(colourBlock);
      }
      else if ((flags & SquishFlags.ColourRangeFit) != 0 || colours.Count == 0) {
        //
        // do a range fit
        //
        RangeFit fit = new RangeFit(colours, flags);

        fit.Compress(colourBlock);
      }
      else {
        //
        // default to a cluster fit (could be iterative or not)
        //
        ClusterFit fit = new ClusterFit(colours, flags);

        fit.Compress(colourBlock);
      }
      //
      // compress alpha separately if necessary
      //
      if ((flags & SquishFlags.Dxt3) != 0) compressAlphaDxt3(rgba, mask, alphaBlock);
      else if ((flags & SquishFlags.Dxt5) != 0) compressAlphaDxt5(rgba, mask, alphaBlock);
    }
示例#42
0
    public unsafe ColourSet(byte *rgba, int mask, SquishFlags flags) {
      Count = 0;

      IsTransparent = false;
      //
      // check the compression mode for dxt1
      //
      bool isDxt1        = (flags & SquishFlags.Dxt1) != 0;
      bool weightByAlpha = (flags & SquishFlags.WeightColourByAlpha) != 0;
      //
      // create the minimal set
      //
      for (int i = 0; i < 16; ++i) {
        //
        // check this pixel is enabled
        //
        int bit = 1 << i;

        if ((mask & bit) == 0) {
          remap[i] = -1;

          continue;
        }
        //
        // check for transparent pixels when using dxt1
        //
        if (isDxt1 && rgba[4 * i + 3] < 128) {
          remap[i] = -1;

          IsTransparent = true;

          continue;
        }
        //
        // loop over previous points for a match
        //
        for(int j = 0; ; ++j) {
          //
          // allocate a new point
          //
          if (j == i) {
            //
            // normalise coordinates to [0,1]
            //
            float x = rgba[4 * i + 0] / 255.0f;
            float y = rgba[4 * i + 1] / 255.0f;
            float z = rgba[4 * i + 2] / 255.0f;
            //
            // ensure there is always non-zero weight even for zero alpha
            //
            float w = (rgba[4 * i + 3] + 1) / 256.0f;
            //
            // add the point
            //
            Points[Count]  = new Vec3(x, y, z);

            Weights[Count] = weightByAlpha ? w : 1.0f;

            remap[i] = Count;
            //
            // advance
            //
            ++Count;

            break;
          }
          //
          // check for a match
          //
          int oldbit = 1 << j;

          bool match = ((mask & oldbit) != 0) && (rgba[4 * i + 0] == rgba[4 * j])
                                              && (rgba[4 * i + 1] == rgba[4 * j + 1])
                                              && (rgba[4 * i + 2] == rgba[4 * j + 2])
                                              && (rgba[4 * j + 3] >= 128 || !isDxt1);

          if (match) {
            //
            // get the index of the match
            //
            int index = remap[j];
            //
            // ensure there is always non-zero weight even for zero alpha
            //
            float w = (rgba[4 * i + 3] + 1) / 256.0f;
            //
            // map to this point and increase the weight
            //
            Weights[index] += weightByAlpha ? w : 1.0f;

            remap[i] = index;

            break;
          }
        }
      }
      //
      // square root the weights
      //
      for (int i = 0; i < Count; ++i) Weights[i] = (float)Math.Sqrt(Weights[i]);
    }
示例#43
0
 /// <summary>
 /// Compress a 4x4 pixel block using the parameters specified in <paramref name="flags"/>.
 /// </summary>
 /// <param name="rgba">Source RGBA block.</param>
 /// <param name="block">Output DXT compressed block.</param>
 /// <param name="flags">Compression flags.</param>
 public static void Compress(IntPtr rgba, IntPtr block, SquishFlags flags)
 {
     CompressFunction(rgba, block, (int)flags);
 }
示例#44
0
 /// <summary>
 /// Decompresses a 4x4 block of pixels.
 /// </summary>
 /// <param name="data">The compressed DXT block.</param>
 /// <param name="flags">Compression flags:
 /// 
 /// The flags parameter should specify either kDxt1, kDxt3 or kDxt5 compression, 
 /// however, DXT1 will be used by default if none is specified. All other flags 
 /// are ignored.</param>
 /// <returns>Return the decompressed block data.</returns>
 public static byte[] Decompress(byte[] data, SquishFlags flags)
 {
     byte[] output = new byte[16 * 4];
     unsafe
     {
         fixed (byte* lpIn = data, lpOut = output)
         {
             Decompress(lpOut, lpIn, flags);
         }
     }
     return output;
 }
 public ColourFit(ColourSet colours, SquishFlags flags)
 {
     m_colours = colours;
     m_flags = flags;
 }
示例#46
0
        /// <summary>
        /// Decompresses an image in memory.
        /// </summary>
        /// <param name="rgba">Storage for the decompressed pixels.</param>
        /// <param name="width">The width of the source image.</param>
        /// <param name="height">The height of the source image.</param>
        /// <param name="blocks">The compressed DXT blocks.</param>
        /// <param name="flags">Compression flags:
        /// 
        /// The flags parameter should specify either kDxt1, kDxt3 or kDxt5 compression, 
	    /// however, DXT1 will be used by default if none is specified. All other flags 
	    /// are ignored.</param>
        public static unsafe void DecompressImage(byte* rgba, int width, int height, byte* blocks, SquishFlags flags)
        {
            // fix any bad flags
            flags = FixFlags(flags);

            // initialise the block input
            byte* sourceBlock = blocks;
            int bytesPerBlock = BytesPerBlock(flags);

            // loop over blocks
            for (int y = 0; y < height; y += 4)
            {
                for (int x = 0; x < width; x += 4)
                {
                    // decompress the block
                    byte[] targetRgba = new byte[4 * 16];
                    fixed (byte* fixTargetRgba = targetRgba)
                    {
                        Decompress(fixTargetRgba, sourceBlock, flags);

                        // write the decompressed pixels to the correct image locations
                        byte* sourcePixel = fixTargetRgba;
                        for (int py = 0; py < 4; ++py)
                        {
                            for (int px = 0; px < 4; ++px)
                            {
                                // get the target location
                                int sx = x + px;
                                int sy = y + py;
                                if (sx < width && sy < height)
                                {
                                    byte* targetPixel = rgba + 4 * (width * sy + sx);

                                    // copy the rgba value
                                    for (int i = 0; i < 4; ++i)
                                        *targetPixel++ = *sourcePixel++;
                                }
                                else
                                {
                                    // skip this pixel as its outside the image
                                    sourcePixel += 4;
                                }
                            }
                        }
                    }
                    // advance
                    sourceBlock += bytesPerBlock;
                }
            }
        }
示例#47
0
 /// <summary>
 /// Compresses a 4x4 block of pixels in BCn format.
 /// </summary>
 /// <param name="rgba">The rgba values of the 16 source pixels.</param>
 /// <param name="block">Storage for the compressed BCn block.</param>
 /// <param name="flags">Compression flags.</param>
 public static unsafe void CompressBC(byte* rgba, byte* block, SquishFlags flags)
 {
     // compress with full mask
     CompressMaskedBC(rgba, 0xffff, block, flags);
 }
示例#48
0
 /// <summary>
 /// Returns the final size in bytes of DXT data compressed with the parameters specified in <paramref name="flags"/>.
 /// </summary>
 /// <param name="width">Source image width.</param>
 /// <param name="height">Source image height.</param>
 /// <param name="flags">Compression parameters.</param>
 /// <returns>Size in bytes of the DXT data.</returns>
 public static int GetStorageRequirements(int width, int height, SquishFlags flags)
 {
     return GetStorageRequirementsFunction(width, height, (int)flags);
 }
示例#49
0
        /// <summary>
        /// Compresses a 4x4 block of pixels.
        /// </summary>
        /// <param name="rgba">The rgba values of the 16 source pixels.</param>
        /// <param name="mask">The valid pixel mask.</param>
        /// <param name="block">Storage for the compressed DXT block.</param>
        /// <param name="flags">Compression flags.</param>
        public static unsafe void CompressMasked(byte* rgba, int mask, byte* block, SquishFlags flags)
        {
            // fix any bad flags
            flags = FixFlags(flags);

            if ((flags & (SquishFlags.BC1 | SquishFlags.BC2 | SquishFlags.BC3 | SquishFlags.BC4 | SquishFlags.BC5)) != 0)
            {
                CompressMaskedBC(rgba, mask, block, flags);
                return;
            }

            // get the block locations
            byte* colourBlock = block;
            byte* alphaBock = block;
            if ((flags & (SquishFlags.Dxt3 | SquishFlags.Dxt5)) != 0)
                colourBlock = block + 8;

            // create the minimal point set
            ColourSet colours = new ColourSet(rgba, mask, flags);

            // check the compression type and compress colour
            if (colours.GetCount() == 1)
            {
                // always do a single colour fit
                SingleColourFit fit = new SingleColourFit(colours, flags);
                fit.Compress(colourBlock);
            }
            else if ((flags & SquishFlags.ColourRangeFit) != 0 || colours.GetCount() == 0)
            {
                // do a range fit
                RangeFit fit = new RangeFit(colours, flags);
                fit.Compress(colourBlock);
            }
            else
            {
                // default to a cluster fit (could be iterative or not)
                ClusterFit fit = new ClusterFit(colours, flags);
                fit.Compress(colourBlock);
            }

            // compress alpha separately if necessary
            if ((flags & SquishFlags.Dxt3) != 0)
                AlphaBlock.CompressAlphaDxt3(rgba, mask, alphaBock);
            else if ((flags & SquishFlags.Dxt5) != 0)
                AlphaBlock.CompressAlphaDxt5(rgba, mask, alphaBock);
        }
示例#50
0
    public ClusterFit(ColourSet Colours, SquishFlags Flags) : base(Colours, Flags) {
      //
      // initialise the metric
      //
      bool isPerceptual = (flags & SquishFlags.ColourMetricPerceptual) != 0;

      metric = isPerceptual ? new Vec3(0.2126f, 0.7152f, 0.0722f) : new Vec3(1.0f);
      //
      // initialise the best error
      //
      bestError = Single.MaxValue;
      //
      // cache some values
      //
      int count = colours.Count;

      Vec3[] values = colours.Points;

      float[] weights = colours.Weights;
      //
      // get the covariance matrix
      //
      Sym3x3 covariance = Maths.ComputeWeightedCovariance(count, values, weights);
      //
      // compute the principle component
      //
      Vec3 principle = Maths.ComputePrincipleComponent(covariance);
      //
      // get the min and max range as the codebook endpoints
      //
      Vec3 startTemp = new Vec3(0.0f);
      Vec3   endTemp = new Vec3(0.0f);

      if (count > 0) {
        //
        // compute the range
        //
        startTemp = endTemp = values[0];

        float min = Vec3.Dot(values[0], principle);

        float max = min;

        for(int i = 1; i < count; ++i) {
          float val = Vec3.Dot(values[i], principle);

          if (val < min) {
            startTemp = values[i];

            min = val;
          }
          else {
            if (val > max) {
              endTemp = values[i];

              max = val;
            }
          }
        }
      }
      //
      // clamp the output to [0, 1]
      //
      Vec3 one  = new Vec3(1.0f);
      Vec3 zero = new Vec3(0.0f);

      startTemp = Vec3.Min(one, Vec3.Max(zero, startTemp));
      endTemp   = Vec3.Min(one, Vec3.Max(zero, endTemp));
      //
      // clamp to the grid and save
      //
      Vec3 grid    = new Vec3(31.0f, 63.0f, 31.0f);
      Vec3 gridrcp = new Vec3(1.0f / 31.0f, 1.0f / 63.0f, 1.0f / 31.0f);
      Vec3 half    = new Vec3(0.5f);

      start = Vec3.Truncate(grid * startTemp + half) * gridrcp;
      end   = Vec3.Truncate(grid * endTemp   + half) * gridrcp;
    }
        public RangeFit(ColourSet colours, SquishFlags flags, float? metric)
            : base(colours, flags)
        {
            // initialise the metric (old perceptual = 0.2126f, 0.7152f, 0.0722f)
            if (metric != null)
            {
                //m_metric = new Vector3( metric[0], metric[1], metric[2] );
            }
            else
            {
                m_metric = new Vector3(1.0f);
            }

            // initialise the best error
            m_besterror = float.MaxValue;

            // cache some values
            int count = m_colours.Count;
            Vector3[] values = m_colours.Points;
            float[] weights = m_colours.Weights;

            // get the covariance matrix
            Sym3x3 covariance = Sym3x3.ComputeWeightedCovariance(count, values, weights);

            // compute the principle component
            Vector3 principle = Sym3x3.ComputePrincipleComponent(covariance);

            // get the min and max range as the codebook endpoints
            Vector3 start = new Vector3(0.0f);
            Vector3 end = new Vector3(0.0f);
            if (count > 0)
            {
                float min, max;

                // compute the range
                start = end = values[0];
                min = max = Vector3.Dot(values[0], principle);
                for (int i = 1; i < count; ++i)
                {
                    float val = Vector3.Dot(values[i], principle);
                    if (val < min)
                    {
                        start = values[i];
                        min = val;
                    }
                    else if (val > max)
                    {
                        end = values[i];
                        max = val;
                    }
                }
            }

            // clamp the output to [0, 1]
            Vector3 one = new Vector3(1.0f);
            Vector3 zero = new Vector3(0.0f);
            start = Vector3.Min(one, Vector3.Max(zero, start));
            end = Vector3.Min(one, Vector3.Max(zero, end));

            // clamp to the grid and save
            Vector3 grid = new Vector3(31.0f, 63.0f, 31.0f);
            Vector3 gridrcp = new Vector3(1.0f / 31.0f, 1.0f / 63.0f, 1.0f / 31.0f);
            Vector3 half = new Vector3(0.5f);
            m_start = Helpers.Truncate(grid * start + half) * gridrcp;
            m_end = Helpers.Truncate(grid * end + half) * gridrcp;
        }
示例#52
0
 /// <summary>
 /// Decompresses a 4x4 block of pixels in BCn format.
 /// </summary>
 /// <param name="rgba">Storage for the 16 decompressed pixels.</param>
 /// <param name="block">The compressed BCn block.</param>
 /// <param name="flags">Compression flags:
 /// 
 /// The flags parameter should specify either BC1, BC2, BC3, BC4 or BC5 compression, 
 /// however. All other flags are ignored.</param>
 public static unsafe void DecompressBC(byte* rgba, byte* block, SquishFlags flags)
 {
     if ((flags & SquishFlags.BC1) != 0)
     {
         SquishFlags cflags = flags;
         cflags = cflags & ~SquishFlags.BC1;
         cflags |= SquishFlags.Dxt1;
         Decompress(rgba, block, cflags);
     }
     else if ((flags & SquishFlags.BC2) != 0)
     {
         SquishFlags cflags = flags;
         cflags = cflags & ~SquishFlags.BC2;
         cflags |= SquishFlags.Dxt3;
         Decompress(rgba, block, cflags);
     }
     else if ((flags & SquishFlags.BC3) != 0)
     {
         SquishFlags cflags = flags;
         cflags = cflags & ~SquishFlags.BC3;
         cflags |= SquishFlags.Dxt5; 
         Decompress(rgba, block, cflags);
     }
     else if ((flags & SquishFlags.BC4) != 0)
     {
         byte[] alpha_array = new byte[8];
         byte[] index_array = new byte[16];
         fixed (byte* fix_alpha = alpha_array, fix_index = index_array)
         {
             AlphaBlock.DecodeDXT5AlphaBlock(block, fix_alpha);
             AlphaBlock.DecodeDXT5AlphaIndices(block, fix_index);
             for (int i = 0, j = 0; i < 16; i++)
             {
                 rgba[j] = fix_alpha[fix_index[i]];
                 rgba[j + 1] = fix_alpha[fix_index[i]];
                 rgba[j + 2] = fix_alpha[fix_index[i]];
                 rgba[j + 3] = 255;
                 j += 4;
             }
         }
     }
     else if ((flags & SquishFlags.BC5) != 0)
     {
         byte[] alpha_array = new byte[8];
         byte[] index_array = new byte[16];
         byte[] reds = new byte[16];
         fixed (byte* fix_alpha = alpha_array, fix_index = index_array)
         {
             AlphaBlock.DecodeDXT5AlphaBlock(block, fix_alpha);
             AlphaBlock.DecodeDXT5AlphaIndices(block, fix_index);
             for (int i = 0; i < 16; i++)
             {
                 reds[i] = fix_alpha[fix_index[i]];
             }
             AlphaBlock.DecodeDXT5AlphaBlock(block, fix_alpha);
             AlphaBlock.DecodeDXT5AlphaIndices(block, fix_index);
             for (int i = 0, j = 0; i < 16; i++)
             {
                 rgba[j] = reds[i]; // red
                 rgba[j + 1] = fix_alpha[fix_index[i]]; // green
                 rgba[j + 2] = 0; // blue
                 rgba[j + 3] = 0xFF; // alpha
                 j += 4;
             }
         }
     }
 }
示例#53
0
        public SingleColourFit(ColourSet colours, SquishFlags flags)
            : base(colours, flags)
        {
            Vec3[] values = m_colours.GetPoints();
            m_colour[0] = (byte)CMath.FloatToInt(255.0f * values[0].X(), 255);
            m_colour[1] = (byte)CMath.FloatToInt(255.0f * values[0].Y(), 255);
            m_colour[2] = (byte)CMath.FloatToInt(255.0f * values[0].Z(), 255);

            // initialise the best error
            m_besterror = int.MaxValue;
        }
示例#54
0
 /// <summary>
 /// Decompresses an image in memory.
 /// </summary>
 /// <param name="data">The compressed DXT blocks.</param>
 /// <param name="width">The width of the source image.</param>
 /// <param name="height">The height of the source image.</param>
 /// <param name="flags">Compression flags:
 /// 
 /// The flags parameter should specify either kDxt1, kDxt3 or kDxt5 compression, 
 /// however, DXT1 will be used by default if none is specified. All other flags 
 /// are ignored.</param>
 /// <returns>Return the Decompressed Image Data.</returns>
 public static byte[] DecompressImage(byte[] data, int width, int height, SquishFlags flags)
 {
     byte[] output = new byte[width * height*4];
     unsafe
     {
         fixed (byte* lpIn = data, lpOut=output)
         {
             DecompressImage(lpOut, width, height, lpIn, flags);
         }
     }
     return output;
 }
示例#55
0
 private static unsafe int SquishGetStorageRequirements(int width, int height, SquishFlags flags)
 {
     if (Is64Bit())
     {
         return(SquishInterface_64.SquishGetStorageRequirements(width, height, (int)flags));
     }
     else
     {
         return(SquishInterface_32.SquishGetStorageRequirements(width, height, (int)flags));
     }
 }
示例#56
0
        /// <summary>
        /// Decompresses an image using the parameters specified in <paramref name="flags"/>.
        /// </summary>
        /// <param name="blocks">Source DXT compressed image.</param>
        /// <param name="width">Width of the image.</param>
        /// <param name="height">Height of the image.</param>
        /// <param name="flags">Decompression flags.</param>
        /// <returns>Output RGBA decompressed image.</returns>
        public static byte[] DecompressImage(byte[] blocks, int width, int height, SquishFlags flags)
        {
            byte[] decompressedData = new byte[width * height * 4];

            GCHandle pinnedData = GCHandle.Alloc(decompressedData, GCHandleType.Pinned);
            GCHandle pinnedBlocks = GCHandle.Alloc(blocks, GCHandleType.Pinned);

            DecompressImageFunction(pinnedData.AddrOfPinnedObject(), width, height, pinnedBlocks.AddrOfPinnedObject(), (int)flags);

            pinnedBlocks.Free();
            pinnedData.Free();

            return decompressedData;
        }
示例#57
0
 private static unsafe void SquishDecompressImage(byte[] rgba, int width, int height, byte[] blocks, SquishFlags flags)
 {
     fixed(byte *pRGBA = rgba)
     fixed(byte *pBlocks = blocks)
     {
         if (Is64Bit())
         {
             SquishInterface_64.SquishDecompressImage(pRGBA, width, height, pBlocks, (int)flags);
         }
         else
         {
             SquishInterface_32.SquishDecompressImage(pRGBA, width, height, pBlocks, (int)flags);
         }
     }
 }
示例#58
0
        /// <summary>
        /// Computes the amount of compressed storage required.
        /// </summary>
        /// <param name="width">The width of the image.</param>
        /// <param name="height">The height of the image.</param>
        /// <param name="flags">Compression flags:
        /// 
        /// The flags parameter should specify either kDxt1, kDxt3 or kDxt5 compression, 
        /// however, DXT1 will be used by default if none is specified. All other flags 
        /// are ignored.</param>
        /// <returns></returns>
        public static int GetStorageRequirements(int width, int height, SquishFlags flags)
        {
            // fix any bad flags
            flags = FixFlags(flags);

            // compute the storage requirements
            int blockcount = GetBlocksCount(width, height);
            int blocksize = BytesPerBlock(flags);
            return blockcount * blocksize;
        }
示例#59
0
    public static unsafe byte[] CompressImage(byte[] rgba, int width, int height, SquishFlags flags, Action<int, int> progressFn) {
      //
      // fix any bad flags
      //
      flags = fixFlags(flags);
      //
      // initialise the block output
      //
      int blockCount = (width + 3 ) / 4 * ((height + 3) / 4);

      int blockSize = (flags & SquishFlags.Dxt1) != 0 ? 8 : 16;

      byte[] blocks = new byte[blockCount * blockSize];

      int progress = 0;

      progressFn?.Invoke(0, height);
      //
      // loop over blocks
      //
      fixed(byte *pBlocks = blocks) {
        byte *targetBlock = pBlocks;

        fixed(byte *pRgba = rgba) {
          byte *source = pRgba;

          Parallel.ForEach(SteppedEnumerable.SteppedRange(0, height, 4), y => {
            Parallel.ForEach(SteppedEnumerable.SteppedRange(0, width, 4), x => {
              //
              // build the 4x4 block of pixels
              //
              byte[] sourceRgba = new byte[16 * 4];

              int mask = 0;

              fixed(byte *pSourceRgba = sourceRgba) {
                byte *targetPixel = pSourceRgba;

                for(int py = 0; py < 4; ++py) {
                  for(int px = 0; px < 4; ++px) {
                    //
                    // get the source pixel in the image
                    //
                    int sx = x + px;
                    int sy = y + py;
                    //
                    // enable if we're in the image
                    //
                    if (sx < width && sy < height) {
                      //
                      // copy the rgba value
                      //
                      byte *sourcePixel = source + 4 * (width * sy + sx);

                      for(int i = 0; i < 4; ++i) *targetPixel++ = *sourcePixel++;
                      //
                      // enable this pixel
                      //
                      mask |= 1 << (4 * py + px);
                    }
                    else {
                      //
                      // skip this pixel as its outside the image
                      //
                      targetPixel += 4;
                    }
                  }
                }
                //
                // compress it into the output
                //
                int blockNum = (width + 3) / 4 * (y / 4) + x / 4;

                byte *outputBlock = targetBlock + blockSize * blockNum;

                compressMasked(pSourceRgba, mask, outputBlock, flags);
              }
            });

            Interlocked.Add(ref progress, 4);

            progressFn?.Invoke(progress, height);
          });
        }
      }

      progressFn?.Invoke(height, height);

      return blocks;
    }
示例#60
0
        /// <summary>
        /// Decompresses a 4x4 block of pixels.
        /// </summary>
        /// <param name="rgba">Storage for the 16 decompressed pixels.</param>
        /// <param name="block">The compressed DXT block.</param>
        /// <param name="flags">Compression flags:
        /// 
        /// The flags parameter should specify either kDxt1, kDxt3 or kDxt5 compression, 
	    /// however, DXT1 will be used by default if none is specified. All other flags 
	    /// are ignored.</param>
        public static unsafe void Decompress(byte* rgba, byte* block, SquishFlags flags)
        {
            // fix any bad flags
            flags = FixFlags(flags);

            if ((flags & (SquishFlags.BC1 | SquishFlags.BC2 | SquishFlags.BC3 | SquishFlags.BC4 | SquishFlags.BC5)) != 0)
            {
                DecompressBC(rgba, block, flags);
                return;
            }

            // get the block locations
            byte* colourBlock = block;
            byte* alphaBock = block;
            if ((flags & (SquishFlags.Dxt3 | SquishFlags.Dxt5)) != 0)
                colourBlock += 8;

            // decompress colour
            ColourBlock.DecompressColour(rgba, colourBlock, (flags & SquishFlags.Dxt1) != 0);

            // decompress alpha separately if necessary
            if ((flags & SquishFlags.Dxt3) != 0)
                AlphaBlock.DecompressAlphaDxt3(rgba, alphaBock);
            else if ((flags & SquishFlags.Dxt5) != 0)
                AlphaBlock.DecompressAlphaDxt5(rgba, alphaBock);
        }