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; }
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; } }
protected override void Compress3(ref byte[] block, int offset) { // declare variables var count = MColours.Count; var two = new Vector4(2.0f); var one = new Vector4(1.0f); var halfHalf2 = new Vector4(0.5f, 0.5f, 0.5f, 0.25f); 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; // 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 half along var part1 = i == 0 ? _mPointsWeights[0] : new Vector4(0.0f); var jmin = i == 0 ? 1 : i; for (var j = jmin; ;) { // last cluster [j,count) is at the end var part2 = _mXsumWsum - part1 - part0; // compute least squares terms directly var alphaxSum = Helpers.MultiplyAdd(part1, halfHalf2, part0); var alpha2Sum = alphaxSum.SplatW(); var betaxSum = Helpers.MultiplyAdd(part1, halfHalf2, part2); var beta2Sum = betaxSum.SplatW(); var alphabetaSum = (part1 * halfHalf2).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; besti = i; bestj = j; besterror = error; bestiteration = iterationIndex; } // 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)) { 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 < count; ++m) { unordered[_mOrder[16 * bestiteration + m]] = 1; } MColours.RemapIndices(unordered, bestindices); // save the block ColourBlock.WriteColourBlock3(beststart.ToVector3(), bestend.ToVector3(), bestindices, ref block, offset); // save the error _mBesterror = besterror; } }