Exemple #1
0
        protected override void Compress4(BlockWindow block)
        {
            // cache some values
            var count  = m_colours.Count;
            var values = m_colours.Points;

            // create a codebook
            var codes = new Vec3[4];

            codes[0] = m_start;
            codes[1] = m_end;
            codes[2] = (2.0f / 3.0f) * m_start + (1.0f / 3.0f) * m_end;
            codes[3] = (1.0f / 3.0f) * m_start + (2.0f / 3.0f) * m_end;

            // match each point to the closest code
            var   closest = new Byte[16];
            float error   = 0.0f;

            for (int i = 0; i < count; ++i)
            {
                // find the closest code
                float dist = float.MaxValue;
                int   idx  = 0;
                for (int j = 0; j < 4; ++j)
                {
                    float d = (m_metric * (values[i] - codes[j])).LengthSquared();
                    if (d < dist)
                    {
                        dist = d;
                        idx  = j;
                    }
                }

                // save the index
                closest[i] = (Byte)idx;

                // accumulate the error
                error += dist;
            }

            // save this scheme if it wins
            if (error < m_besterror)
            {
                // remap the indices
                var indices = new Byte[16];
                m_colours.RemapIndices(closest, indices);

                // save the block
                block.WriteColourBlock4(m_start, m_end, indices);

                // save the error
                m_besterror = error;
            }
        }
Exemple #2
0
 public void Compress(BlockWindow block)
 {
     if (block.IsDtx1)
     {
         if (m_colours.IsTransparent)
         {
             Compress3(block);
         }
         else
         {
             Compress4(block);
         }
     }
     else
     {
         Compress4(block);
     }
 }
        protected override void Compress4(BlockWindow block)
        {
            // find the best end-points and index
            ComputeEndPoints(LOOKUPTABLES4);

            // build the block if we win
            if (m_error < m_besterror)
            {
                // remap the indices
                var indices = new Byte[16];
                m_colours.RemapIndices(new Byte[] { m_index }, indices);

                // save the block
                block.WriteColourBlock4(m_start, m_end, indices);

                // save the error
                m_besterror = m_error;
            }
        }
Exemple #4
0
        private static void DecompressImage(Bitmap dstImage, Byte[] blocks, CompressionMode mode)
        {
            // initialise the block input
            var block = new BlockWindow(blocks, mode);

            var targetRgba = new Byte[4 * 16];

            // loop over blocks
            for (int y = 0; y < dstImage.Height; y += 4)
            {
                for (int x = 0; x < dstImage.Width; x += 4)
                {
                    // decompress the block
                    block.Decompress(targetRgba);

                    // write the decompressed pixels to the correct image locations
                    dstImage.SetBlock(x, y, targetRgba);

                    // advance
                    block.Offset += block.ByteLength;
                }
            }
        }
Exemple #5
0
 protected abstract void Compress4(BlockWindow block);
Exemple #6
0
        protected override void Compress3(BlockWindow block)
        {
            // prepare an ordering using the principle axis
            ConstructOrdering(m_principle);

            // declare variables
            int count = m_colours.Count;

            Vec4 beststart = Vec4.Zero;
            Vec4 bestend   = Vec4.Zero;

            var besterror     = float.MaxValue;
            var bestbesterror = float.MaxValue;

            // check all possible clusters for this total order
            var indices     = new Byte[16];
            var bestindices = new Byte[16];

            // first cluster [0,i) is at the start
            for (int m = 0; m < count; ++m)
            {
                indices[m] = 0;
                m_alpha[m] = m_weights[m];
                m_beta[m]  = 0;
            }

            for (int i = count; i >= 0; --i)
            {
                // second cluster [i,j) is half along
                for (int m = i; m < count; ++m)
                {
                    indices[m] = 2;
                    m_alpha[m] = m_beta[m] = 0.5f * m_weights[m];
                }

                for (int j = count; j > i; --j)
                {
                    // last cluster [j,k) is at the end
                    if (j < count)
                    {
                        indices[j] = 1;
                        m_alpha[j] = 0;
                        m_beta[j]  = m_weights[j];
                    }

                    // solve a least squares problem to place the endpoints
                    var error = SolveLeastSquares(out Vec4 start, out Vec4 end);

                    // keep the solution if it wins
                    if (error < besterror)
                    {
                        beststart = start;
                        bestend   = end;
                        indices.CopyTo(bestindices, 0);
                        besterror = error;
                    }
                }
            }

            // save the block if necessary
            if (besterror < bestbesterror)
            {
                // remap the indices
                var unordered = new Byte[16];
                for (int i = 0; i < count; ++i)
                {
                    unordered[m_order[i]] = bestindices[i];
                }
                m_colours.RemapIndices(unordered, bestindices);

                // save the block
                block.WriteColourBlock3(beststart.GetVec3(), bestend.GetVec3(), bestindices);

                // save the error
                bestbesterror = besterror;
            }
        }
Exemple #7
0
        private static void CompressImage(Bitmap srcImage, Byte[] blocks, CompressionMode mode, CompressionOptions options)
        {
            // fix any bad flags
            options = options.FixFlags();

            int block_width  = (srcImage.Width + 3) / 4;
            int block_height = (srcImage.Height + 3) / 4;

            // if the number of chunks to process is not very large, we better skip parallel processing
            if (block_width * block_height < 16)
            {
                options &= ~CompressionOptions.UseParallelProcessing;
            }

            if ((options & CompressionOptions.UseParallelProcessing) != 0)
            {
                System.Threading.Tasks.Parallel.For
                (
                    0,
                    block_height,
                    (y, state) =>
                {
                    // initialise the block output
                    var block = new BlockWindow(blocks, mode);

                    block.Offset += block.ByteLength * y * block_width;

                    // build the 4x4 block of pixels
                    var sourceRgba = new Byte[16 * 4];

                    for (int x = 0; x < block_width; x++)
                    {
                        srcImage.CopyBlockTo(x * 4, y * 4, sourceRgba, out int mask);

                        // compress it into the output
                        block.CompressMasked(sourceRgba, mask, options);

                        // advance
                        block.Offset += block.ByteLength;
                    }
                }
                );
            }
            else
            {
                // initialise the block output
                var block = new BlockWindow(blocks, mode);

                // build the 4x4 block of pixels
                var sourceRgba = new Byte[16 * 4];

                // loop over blocks
                for (int y = 0; y < block_height; ++y)
                {
                    for (int x = 0; x < block_width; ++x)
                    {
                        srcImage.CopyBlockTo(x * 4, y * 4, sourceRgba, out int mask);

                        // compress it into the output
                        block.CompressMasked(sourceRgba, mask, options);

                        // advance
                        block.Offset += block.ByteLength;
                    }
                }
            }
        }
Exemple #8
0
        protected override void Compress4(BlockWindow block)
        {
            // declare variables
            var count = m_colours.Count;

            // prepare an ordering using the principle axis
            ConstructOrdering(m_principle, 0);

            // check all possible clusters and iterate on the total order
            Vec4  beststart = Vec4.Zero;
            Vec4  bestend = Vec4.Zero;
            float m_besterror = float.MaxValue;
            float besterror = m_besterror;
            var   bestindices = new Byte[16];
            int   bestiteration = 0;
            int   besti = 0, bestj = 0, bestk = 0;

            // loop over iterations (we avoid the case that all points in first or last cluster)
            for (int iterationIndex = 0; ;)
            {
                // first cluster [0,i) is at the start
                Vec4 part0 = Vec4.Zero;
                for (int i = 0; i < count; ++i)
                {
                    // second cluster [i,j) is one third along
                    Vec4 part1 = Vec4.Zero;
                    for (int j = i; ;)
                    {
                        // third cluster [j,k) is two thirds along
                        Vec4 part2 = (j == 0) ? m_points_weights[0] : Vec4.Zero;
                        int  kmin  = (j == 0) ? 1 : j;
                        for (int k = kmin; ;)
                        {
                            // last cluster [k,count) is at the end
                            Vec4 part3 = m_xsum_wsum - part2 - part1 - part0;

                            // compute least squares terms directly
                            Vec4 alphax_sum    = ONETHIRD_ONETHIRD2.MultiplyAdd(part2, TWOTHIRDS_TWOTHIRDS2.MultiplyAdd(part1, part0));
                            Vec4 betax_sum     = ONETHIRD_ONETHIRD2.MultiplyAdd(part1, TWOTHIRDS_TWOTHIRDS2.MultiplyAdd(part2, part3));
                            Vec4 alphabeta_sum = TWONINETHS * (part1 + part2).SplatW();

                            var error = ComputeLeastSquares(alphax_sum, betax_sum, alphabeta_sum, out Vec4 a, out Vec4 b);

                            // keep the solution if it wins
                            if (error < besterror)
                            {
                                beststart     = a;
                                bestend       = b;
                                besterror     = error;
                                besti         = i;
                                bestj         = j;
                                bestk         = k;
                                bestiteration = iterationIndex;
                            }

                            // advance
                            if (k == count)
                            {
                                break;
                            }
                            part2 += m_points_weights[k];
                            ++k;
                        }

                        // advance
                        if (j == count)
                        {
                            break;
                        }
                        part1 += m_points_weights[j];
                        ++j;
                    }

                    // advance
                    part0 += m_points_weights[i];
                }

                // stop if we didn't improve in this iteration
                if (bestiteration != iterationIndex)
                {
                    break;
                }

                // advance if possible
                ++iterationIndex;
                if (iterationIndex == m_iterationCount)
                {
                    break;
                }

                // stop if a new iteration is an ordering that has already been tried
                Vec3 axis = (bestend - beststart).GetVec3();
                if (!ConstructOrdering(axis, iterationIndex))
                {
                    break;
                }
            }

            // save the block if necessary
            if (besterror < m_besterror)
            {
                // remap the indices
                var orderIndex = 16 * bestiteration;

                var unordered = new Byte[16];
                for (int m = 0; m < besti; ++m)
                {
                    unordered[m_order[orderIndex + m]] = 0;
                }
                for (int m = besti; m < bestj; ++m)
                {
                    unordered[m_order[orderIndex + m]] = 2;
                }
                for (int m = bestj; m < bestk; ++m)
                {
                    unordered[m_order[orderIndex + m]] = 3;
                }
                for (int m = bestk; m < count; ++m)
                {
                    unordered[m_order[orderIndex + m]] = 1;
                }

                m_colours.RemapIndices(unordered, bestindices);

                // save the block
                block.WriteColourBlock4(beststart.GetVec3(), bestend.GetVec3(), bestindices);

                // save the error
                m_besterror = besterror;
            }
        }