예제 #1
0
        public override void Compress4(ref byte[] block, int offset)
        {
            // build the table of lookups
            SingleColourLookup[][] lookups = new SingleColourLookup[][]
            {
                SingleColourLookupIns.lookup_5_4,
                SingleColourLookupIns.lookup_6_4,
                SingleColourLookupIns.lookup_5_4
            };

            // find the best end-points and index
            ComputeEndPoints(lookups);

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

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

                // save the error
                m_besterror = m_error;
            }
        }
예제 #2
0
        public override void Compress4(ref byte[] block, int offset)
        {
            // declare variables
            int     count = m_colours.Count;
            Vector4 two   = new Vector4(2.0f);
            Vector4 one   = new Vector4(1.0f);
            Vector4 onethird_onethird2   = new Vector4(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 9.0f);
            Vector4 twothirds_twothirds2 = new Vector4(2.0f / 3.0f, 2.0f / 3.0f, 2.0f / 3.0f, 4.0f / 9.0f);
            Vector4 twonineths           = new Vector4(2.0f / 9.0f);
            Vector4 zero    = new Vector4(0.0f);
            Vector4 half    = new Vector4(0.5f);
            Vector4 grid    = new Vector4(31.0f, 63.0f, 31.0f, 0.0f);
            Vector4 gridrcp = new Vector4(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
            Vector4 beststart = new Vector4(0.0f);
            Vector4 bestend   = new Vector4(0.0f);
            Vector4 besterror = m_besterror;

            byte[] 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
                Vector4 part0 = new Vector4(0.0f);
                for (int i = 0; i < count; ++i)
                {
                    // second cluster [i,j) is one third along
                    Vector4 part1 = new Vector4(0.0f);
                    for (int j = i; ;)
                    {
                        // third cluster [j,k) is two thirds along
                        Vector4 part2 = (j == 0) ? m_points_weights[0] : new Vector4(0.0f);
                        int     kmin  = (j == 0) ? 1 : j;
                        for (int k = kmin; ;)
                        {
                            // last cluster [k,count) is at the end
                            Vector4 part3 = m_xsum_wsum - part2 - part1 - part0;

                            // compute least squares terms directly
                            Vector4 alphax_sum = Helpers.MultiplyAdd(part2, onethird_onethird2, Helpers.MultiplyAdd(part1, twothirds_twothirds2, part0));
                            Vector4 alpha2_sum = alphax_sum.SplatW();

                            Vector4 betax_sum = Helpers.MultiplyAdd(part1, onethird_onethird2, Helpers.MultiplyAdd(part2, twothirds_twothirds2, part3));
                            Vector4 beta2_sum = betax_sum.SplatW();

                            Vector4 alphabeta_sum = twonineths * (part1 + part2).SplatW();

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

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

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

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

                            // keep the solution if it wins
                            if (Helpers.CompareAnyLessThan(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
                Vector3 axis = (bestend - beststart).ToVector3();
                if (!ConstructOrdering(axis, iterationIndex))
                {
                    break;
                }
            }

            // save the block if necessary
            if (Helpers.CompareAnyLessThan(besterror, m_besterror))
            {
                // remap the indices
                byte[] unordered = new byte[16];
                for (int m = 0; m < besti; ++m)
                {
                    unordered[m_order[(16 * bestiteration) + m]] = 0;
                }
                for (int m = besti; m < bestj; ++m)
                {
                    unordered[m_order[(16 * bestiteration) + m]] = 2;
                }
                for (int m = bestj; m < bestk; ++m)
                {
                    unordered[m_order[(16 * bestiteration) + m]] = 3;
                }
                for (int m = bestk; m < count; ++m)
                {
                    unordered[m_order[(16 * bestiteration) + m]] = 1;
                }

                m_colours.RemapIndices(unordered, bestindices);

                // save the block
                ColourBlock.WriteColourBlock4(beststart.ToVector3(), bestend.ToVector3(), bestindices, ref block, offset);

                // save the error
                m_besterror = besterror;
            }
        }