public static byte[] DecompressBlock(byte[] block, int blockOffset, SquishOptions flags) { // Get the block locations var colOff = blockOffset; var alphaOff = blockOffset; if ((flags & (SquishOptions.DXT3 | SquishOptions.DXT5)) != 0) { colOff += 8; } // Decompress colour. var rgba = ColourBlock.DecompressColour(block, colOff, flags.HasFlag(SquishOptions.DXT1)); // Decompress alpha seperately if necessary. if (flags.HasFlag(SquishOptions.DXT3)) { Alpha.DecompressAlphaDxt3(block, alphaOff, rgba, 0); } else if (flags.HasFlag(SquishOptions.DXT5)) { Alpha.DecompressAlphaDxt5(block, alphaOff, rgba, 0); } return(rgba); }
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; } }
static void CompressAlphaDxt3(byte[] rgba, int mask, ref byte[] block, int offset) { // quantise and pack the alpha values pairwise for (int i = 0; i < 8; ++i) { // quantise down to 4 bits float alpha1 = (float)rgba[8 * i + 3] * (15.0f / 255.0f); float alpha2 = (float)rgba[8 * i + 7] * (15.0f / 255.0f); int quant1 = ColourBlock.FloatToInt(alpha1, 15); int quant2 = ColourBlock.FloatToInt(alpha2, 15); // set alpha to zero where masked int bit1 = 1 << (2 * i); int 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)); } }
static void Decompress(byte[] rgba, ref byte[] block, int offset, SquishFlags flags) { // fix any bad flags flags = FixFlags(flags); // get the block locations int colourBlock = offset; int 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); } else if ((flags & SquishFlags.kDxt5) != 0) { DecompressAlphaDxt5(rgba, ref block, alphaBlock); } }
public override void Compress3(ref byte[] block, int offset) { // cache some values int count = m_colours.Count; Vector3[] values = m_colours.Points; // create a codebook Vector3[] codes = new Vector3[3]; codes[0] = m_start; codes[1] = m_end; codes[2] = 0.5f * m_start + 0.5f * m_end; // match each point to the closest code byte[] 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 < 3; ++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 byte[] indices = new byte[16]; m_colours.RemapIndices(closest, indices); // save the block ColourBlock.WriteColourBlock3(m_start, m_end, indices, ref block, offset); // save the error m_besterror = error; } }
public SingleColourFit(ColourSet colours, SquishFlags flags) : base(colours, flags) { // grab the single colour Vector3[] values = m_colours.Points; m_colour[0] = (byte)ColourBlock.FloatToInt(255.0f * values[0].X, 255); m_colour[1] = (byte)ColourBlock.FloatToInt(255.0f * values[0].Y, 255); m_colour[2] = (byte)ColourBlock.FloatToInt(255.0f * values[0].Z, 255); // initialise the best error m_besterror = int.MaxValue; }
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; } }