Exemple #1
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);
        }
Exemple #2
0
 public static bool CompareAnyLessThan(Vec4 a, Vec4 b)
 {
     return a.X() < b.X()
         || a.Y() < b.Y()
         || a.Z() < b.Z()
         || a.W() < b.W();
 }
Exemple #3
0
 public static Vec4 Truncate(Vec4 v)
 {
     return new Vec4(
         v.X() > 0.0f ? CMath.Floor(v.X()) : CMath.Ceil(v.X()),
         v.Y() > 0.0f ? CMath.Floor(v.Y()) : CMath.Ceil(v.Y()),
         v.Z() > 0.0f ? CMath.Floor(v.Z()) : CMath.Ceil(v.Z()),
         v.W() > 0.0f ? CMath.Floor(v.W()) : CMath.Ceil(v.W())
     );
 }
Exemple #4
0
 public static Vec4 Max(Vec4 a, Vec4 b)
 {
     return new Vec4(
         Math.Max(a.X(), b.X()),
         Math.Max(a.Y(), b.Y()),
         Math.Max(a.Z(), b.Z()),
         Math.Max(a.W(), b.W())
     );
 }
Exemple #5
0
 public static Vec4 Reciprocal(Vec4 v)
 {
     return new Vec4(
         1.0f / v.X(),
         1.0f / v.Y(),
         1.0f / v.Z(),
         1.0f / v.W()
     );
 }
Exemple #6
0
 public static Vec4 NegativeMultiplySubtract(Vec4 a, Vec4 b, Vec4 c)
 {
     return c - a * b;
 }
Exemple #7
0
 public static Vec4 MultiplyAdd(Vec4 a, Vec4 b, Vec4 c)
 {
     return a * b + c;
 }
Exemple #8
0
        protected override unsafe void Compress3(byte* block)
        {
            // declare variables
            int count = m_colours.GetCount();
            Vec4 two = new Vec4(2.0f);
            Vec4 one = new Vec4(1.0f);
            Vec4 half_half2 = new Vec4(0.5f, 0.5f, 0.5f, 0.25f);
            Vec4 zero = new Vec4(0.0f);
            Vec4 half = new Vec4(0.5f);
            Vec4 grid = new Vec4(31.0f, 63.0f, 31.0f, 0.0f);
            Vec4 gridrcp = new Vec4(1.0f / 31.0f, 1.0f / 63.0f, 1.0f / 31.0f, 0.0f);
            // prepare an ordering using the principle axis
            ConstructOrdering(m_principle, 0);

            // check all possible clusters and iterate on the total order
            Vec4 beststart = new Vec4(0.0f);
            Vec4 bestend = new Vec4(0.0f);
            Vec4 besterror = m_besterror;
            byte[] bestindices = new byte[16];
            int bestiteration = 0;
            int besti = 0, bestj = 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 = new Vec4(0.0f);
                for (int i = 0; i < count; ++i)
                {
                    // second cluster [i,j) is half along
                    Vec4 part1 = (i == 0) ? m_points_weights[0] : new Vec4(0.0f);
                    int jmin = (i == 0) ? 1 : i;
                    for (int j = jmin; ; )
                    {
                        // last cluster [j,count) is at the end
                        Vec4 part2 = m_xsum_wsum - part1 - part0;

                        // compute least squares terms directly
                        Vec4 alphax_sum = Vec4.MultiplyAdd(part1, half_half2, part0);
                        Vec4 alpha2_sum = alphax_sum.SplatW();

                        Vec4 betax_sum = Vec4.MultiplyAdd(part1, half_half2, part2);
                        Vec4 beta2_sum = betax_sum.SplatW();

                        Vec4 alphabeta_sum = (part1 * half_half2).SplatW();

                        // compute the least-squares optimal points
                        Vec4 factor = Vec4.Reciprocal(Vec4.NegativeMultiplySubtract(alphabeta_sum, alphabeta_sum, alpha2_sum * beta2_sum));
                        Vec4 a = Vec4.NegativeMultiplySubtract(betax_sum, alphabeta_sum, alphax_sum * beta2_sum) * factor;
                        Vec4 b = Vec4.NegativeMultiplySubtract(alphax_sum, alphabeta_sum, betax_sum * alpha2_sum) * factor;

                        // clamp to the grid
                        a = Vec4.Min(one, Vec4.Max(zero, a));
                        b = Vec4.Min(one, Vec4.Max(zero, b));
                        a = Vec4.Truncate(Vec4.MultiplyAdd(grid, a, half)) * gridrcp;
                        b = Vec4.Truncate(Vec4.MultiplyAdd(grid, b, half)) * gridrcp;

                        // compute the error (we skip the constant xxsum)
                        Vec4 e1 = Vec4.MultiplyAdd(a * a, alpha2_sum, b * b * beta2_sum);
                        Vec4 e2 = Vec4.NegativeMultiplySubtract(a, alphax_sum, a * b * alphabeta_sum);
                        Vec4 e3 = Vec4.NegativeMultiplySubtract(b, betax_sum, e2);
                        Vec4 e4 = Vec4.MultiplyAdd(two, e3, e1);

                        // apply the metric to the error term
                        Vec4 e5 = e4 * m_metric;
                        Vec4 error = e5.SplatX() + e5.SplatY() + e5.SplatZ();

                        // keep the solution if it wins
                        if (Vec4.CompareAnyLessThan(error, besterror))
                        {
                            beststart = a;
                            bestend = b;
                            besti = i;
                            bestj = j;
                            besterror = error;
                            bestiteration = iterationIndex;
                        }

                        // 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 (Vec4.CompareAnyLessThan(besterror, m_besterror))
            {
                // remap the indices
                int orderIndex = 16 * bestiteration;
                byte[] 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 < count; ++m)
                    unordered[m_order[orderIndex + m]] = 1;

                fixed (byte* fixUnordered = unordered, fixBestIndices = bestindices)
                {
                    m_colours.RemapIndices(fixUnordered, fixBestIndices);
                    // save the block
                    ColourBlock.WriteColourBlock3(beststart.GetVec3(), bestend.GetVec3(), fixBestIndices, block);
                }
                // save the error
                m_besterror = besterror;
            }
        }
Exemple #9
0
        private bool ConstructOrdering(Vec3 axis, int iteration)
        {
            // cache some values
            int count = m_colours.GetCount();
            Vec3[] values = m_colours.GetPoints();

            // build the list of dot products
            float[] dps = new float[16];
            int orderIndex = 16 * iteration;
            for (int i = 0; i < count; ++i)
            {
                dps[i] = Vec3.Dot(values[i], axis);
                m_order[orderIndex + i] = (byte)i;
            }
            // stable sort using them
            for (int i = 0; i < count; ++i)
            {
                for (int j = i; j > 0 && dps[j] < dps[j - 1]; --j)
                {
                    CMath.Swap<float>(ref dps[j], ref dps[j - 1]);
                    CMath.Swap<byte>(ref m_order[orderIndex + j], ref m_order[orderIndex + (j - 1)]);
                }
            }
            // check this ordering is unique
            for (int it = 0; it < iteration; ++it)
            {
                int prevIndex = 16 * it;
                bool same = true;
                for (int i = 0; i < count; ++i)
                {
                    if (m_order[orderIndex + i] != m_order[prevIndex + i])
                    {
                        same = false;
                        break;
                    }
                }
                if (same)
                    return false;
            }
            // copy the ordering and weight all the points
            Vec3[] unweighted = m_colours.GetPoints();
            float[] weights = m_colours.GetWeights();
            m_xsum_wsum = new Vec4(0.0f);
            for (int i = 0; i < count; ++i)
            {
                int j = m_order[orderIndex + i];
                Vec4 p = new Vec4(unweighted[j].X(), unweighted[j].Y(), unweighted[j].Z(), 1.0f);
                Vec4 w = new Vec4(weights[j]);
                Vec4 x = p * w;
                m_points_weights[i] = x;
                m_xsum_wsum += x;
            }
            return true;
        }