Пример #1
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);
            }
        }
Пример #2
0
        private static void CompressAlphaDxt3(byte[] rgba, int mask, ref byte[] block, int offset)
        {
            // quantise and pack the alpha values pairwise
            for (var i = 0; i < 8; ++i)
            {
                // quantise down to 4 bits
                var alpha1 = rgba[8 * i + 3] * (15.0f / 255.0f);
                var alpha2 = rgba[8 * i + 7] * (15.0f / 255.0f);
                var quant1 = ColourBlock.FloatToInt(alpha1, 15);
                var quant2 = ColourBlock.FloatToInt(alpha2, 15);

                // set alpha to zero where masked
                var bit1 = 1 << (2 * i);
                var bit2 = 1 << (2 * i + 1);
                if ((mask & bit1) == 0)
                {
                    quant1 = 0;
                }
                if ((mask & bit2) == 0)
                {
                    quant2 = 0;
                }

                // pack into the byte
                block[i + offset] = (byte)(quant1 | (quant2 << 4));
            }
        }
Пример #3
0
        protected override void Compress3(ref byte[] block, int offset)
        {
            // build the table of lookups
            var lookups = new[]
            {
                SingleColourLookupIns.Lookup53,
                SingleColourLookupIns.Lookup63,
                SingleColourLookupIns.Lookup53
            };

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

            // build the block if we win
            if (_mError >= _mBesterror)
            {
                return;
            }

            // remap the indices
            var indices = new byte[16];

            MColours.RemapIndices(new[] { _mIndex }, indices);

            // save the block
            ColourBlock.WriteColourBlock3(_mStart, _mEnd, indices, ref block, offset);

            // save the error
            _mBesterror = _mError;
        }
Пример #4
0
        protected override void Compress3(ref byte[] block, int offset)
        {
            // cache some values
            var count  = MColours.Count;
            var values = MColours.Points;

            // create a codebook
            var codes = new Vector3[3];

            codes[0] = _mStart;
            codes[1] = _mEnd;
            codes[2] = 0.5f * _mStart + 0.5f * _mEnd;

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

            for (var i = 0; i < count; ++i)
            {
                // find the closest code
                var dist = float.MaxValue;
                var idx  = 0;
                for (var j = 0; j < 3; ++j)
                {
                    var d = (_mMetric * (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 < _mBesterror)
            {
                // remap the indices
                var indices = new byte[16];
                MColours.RemapIndices(closest, indices);

                // save the block
                ColourBlock.WriteColourBlock3(_mStart, _mEnd, indices, ref block, offset);

                // save the error
                _mBesterror = error;
            }
        }
Пример #5
0
        public SingleColourFit(ColourSet colours, SquishFlags flags)
            : base(colours, flags)
        {
            // grab the single colour
            var values = MColours.Points;

            _mColour[0] = (byte)ColourBlock.FloatToInt(255.0f * values[0].X, 255);
            _mColour[1] = (byte)ColourBlock.FloatToInt(255.0f * values[0].Y, 255);
            _mColour[2] = (byte)ColourBlock.FloatToInt(255.0f * values[0].Z, 255);

            // initialise the best error
            _mBesterror = int.MaxValue;
        }
Пример #6
0
        protected override void Compress4(ref byte[] block, int offset)
        {
            // declare variables
            var count               = MColours.Count;
            var two                 = new Vector4(2.0f);
            var one                 = new Vector4(1.0f);
            var onethirdOnethird2   = new Vector4(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 9.0f);
            var twothirdsTwothirds2 = new Vector4(2.0f / 3.0f, 2.0f / 3.0f, 2.0f / 3.0f, 4.0f / 9.0f);
            var twonineths          = new Vector4(2.0f / 9.0f);
            var zero                = new Vector4(0.0f);
            var half                = new Vector4(0.5f);
            var grid                = new Vector4(31.0f, 63.0f, 31.0f, 0.0f);
            var 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(_mPrinciple, 0);

            // check all possible clusters and iterate on the total order
            var beststart = new Vector4(0.0f);
            var bestend = new Vector4(0.0f);
            var besterror = _mBesterror;
            var bestindices = new byte[16];
            var 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 (var iterationIndex = 0; ;)
            {
                // first cluster [0,i) is at the start
                var part0 = new Vector4(0.0f);
                for (var i = 0; i < count; ++i)
                {
                    // second cluster [i,j) is one third along
                    var part1 = new Vector4(0.0f);
                    for (var j = i; ;)
                    {
                        // third cluster [j,k) is two thirds along
                        var part2 = j == 0 ? _mPointsWeights[0] : new Vector4(0.0f);
                        var kmin  = j == 0 ? 1 : j;
                        for (var k = kmin; ;)
                        {
                            // last cluster [k,count) is at the end
                            var part3 = _mXsumWsum - part2 - part1 - part0;

                            // compute least squares terms directly
                            var alphaxSum = Helpers.MultiplyAdd(part2, onethirdOnethird2, Helpers.MultiplyAdd(part1, twothirdsTwothirds2, part0));
                            var alpha2Sum = alphaxSum.SplatW();

                            var betaxSum = Helpers.MultiplyAdd(part1, onethirdOnethird2, Helpers.MultiplyAdd(part2, twothirdsTwothirds2, part3));
                            var beta2Sum = betaxSum.SplatW();

                            var alphabetaSum = twonineths * (part1 + part2).SplatW();

                            // compute the least-squares optimal points
                            var factor = Helpers.Reciprocal(Helpers.NegativeMultiplySubtract(alphabetaSum, alphabetaSum, alpha2Sum * beta2Sum));
                            var a      = Helpers.NegativeMultiplySubtract(betaxSum, alphabetaSum, alphaxSum * beta2Sum) * factor;
                            var b      = Helpers.NegativeMultiplySubtract(alphaxSum, alphabetaSum, betaxSum * alpha2Sum) * 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)
                            var e1 = Helpers.MultiplyAdd(a * a, alpha2Sum, b * b * beta2Sum);
                            var e2 = Helpers.NegativeMultiplySubtract(a, alphaxSum, a * b * alphabetaSum);
                            var e3 = Helpers.NegativeMultiplySubtract(b, betaxSum, e2);
                            var e4 = Helpers.MultiplyAdd(two, e3, e1);

                            // apply the metric to the error term
                            var e5    = e4 * _mMetric;
                            var 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 += _mPointsWeights[k];
                            ++k;
                        }

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

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

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

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

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

            // save the block if necessary
            if (!Helpers.CompareAnyLessThan(besterror, _mBesterror))
            {
                return;
            }

            // remap the indices
            var unordered = new byte[16];

            for (var m = 0; m < besti; ++m)
            {
                unordered[_mOrder[16 * bestiteration + m]] = 0;
            }

            for (var m = besti; m < bestj; ++m)
            {
                unordered[_mOrder[16 * bestiteration + m]] = 2;
            }

            for (var m = bestj; m < bestk; ++m)
            {
                unordered[_mOrder[16 * bestiteration + m]] = 3;
            }

            for (var m = bestk; m < count; ++m)
            {
                unordered[_mOrder[16 * bestiteration + m]] = 1;
            }

            MColours.RemapIndices(unordered, bestindices);

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

            // save the error
            _mBesterror = besterror;
        }