void compressDXT5A(ColorBlock src, AlphaBlockDXT5 dst) { AlphaBlock4x4 tmp = new AlphaBlock4x4(); tmp.init(src, 3); compressDXT5A(tmp, dst); }
/*static uint computeAlphaError8( ColorBlock & rgba, AlphaBlockDXT5 * block, int bestError = INT_MAX) * { * int totalError = 0; * * for (uint i = 0; i < 16; i++) * { * byte alpha = rgba.color[i].a; * * totalError += alphaDistance(alpha, nearestAlpha8(alpha, block.alpha0, block.alpha1)); * * if (totalError > bestError) * { * // early out * return totalError; * } * } * * return totalError; * }*/ static float computeAlphaError(AlphaBlock4x4 src, AlphaBlockDXT5 dst, float bestError = float.MaxValue) { byte[] alphas = new byte[8]; dst.evaluatePalette(alphas, false); // @@ Use target decoder. float totalError = 0; for (uint i = 0; i < 16; i++) { byte alpha = src.alpha[i]; uint minDist = int.MaxValue; for (uint p = 0; p < 8; p++) { uint dist = alphaDistance(alpha, alphas[p]); minDist = Math.Min(dist, minDist); } totalError += minDist * src.weights[i]; if (totalError > bestError) { // early out return(totalError); } } return(totalError); }
public static void compressDXT5A(ColorBlock src, ref AlphaBlockDXT5 dst, int iterationCount = 8) { AlphaBlock4x4 tmp = new AlphaBlock4x4(); tmp.init(src, 3); compressDXT5A(tmp, ref dst, iterationCount); }
static uint computeAlphaIndices(AlphaBlock4x4 src, AlphaBlockDXT5 block) { byte[] alphas = new byte[8]; block.evaluatePalette(alphas, false); // @@ Use target decoder. uint totalError = 0; for (uint i = 0; i < 16; i++) { byte alpha = src.alpha[i]; uint besterror = 256 * 256; uint best = 8; for (uint p = 0; p < 8; p++) { int d = alphas[p] - alpha; uint error = (uint)(d * d); if (error < besterror) { besterror = error; best = p; } } //nvDebugCheck(best < 8); totalError += besterror; block.setIndex(i, best); } return(totalError); }
static void compressDXT5A(AlphaBlock4x4 src, ref AlphaBlockDXT5 dst, int iterationCount = 8) { byte alpha0 = 0; byte alpha1 = 255; // Get min/max alpha. for (uint i = 0; i < 16; i++) { byte alpha = src.alpha[i]; alpha0 = Math.Max(alpha0, alpha); alpha1 = Math.Min(alpha1, alpha); } AlphaBlockDXT5 block = new AlphaBlockDXT5(); block.alpha0 = (byte)(alpha0 - (alpha0 - alpha1) / 34); block.alpha1 = (byte)(alpha1 + (alpha0 - alpha1) / 34); uint besterror = computeAlphaIndices(src, block); AlphaBlockDXT5 bestblock = block; for (int i = 0; i < iterationCount; i++) { optimizeAlpha8(src, block); uint error = computeAlphaIndices(src, block); if (error >= besterror) { // No improvement, stop. break; } if (sameIndices(block, bestblock)) { bestblock = block; break; } besterror = error; bestblock = block; } ; // Copy best block to result; dst = bestblock; }
static void computeAlphaIndices(AlphaBlock4x4 src, AlphaBlockDXT5 dst) { byte[] alphas = new byte[8]; dst.evaluatePalette(alphas, /*d3d9=*/ false); // @@ Use target decoder. for (uint i = 0; i < 16; i++) { byte alpha = src.alpha[i]; uint minDist = int.MaxValue; uint bestIndex = 8; for (uint p = 0; p < 8; p++) { uint dist = alphaDistance(alpha, alphas[p]); if (dist < minDist) { minDist = dist; bestIndex = p; } } dst.setIndex(i, bestIndex); } }
void compressDXT5A(AlphaBlock4x4 src, AlphaBlockDXT5 dst) { byte mina = 255; byte maxa = 0; byte mina_no01 = 255; byte maxa_no01 = 0; // Get min/max alpha. for (uint i = 0; i < 16; i++) { byte alpha = src.alpha[i]; mina = Math.Min(mina, alpha); maxa = Math.Max(maxa, alpha); if (alpha != 0 && alpha != 255) { mina_no01 = Math.Min(mina_no01, alpha); maxa_no01 = Math.Max(maxa_no01, alpha); } } if (maxa - mina < 8) { dst.alpha0 = maxa; dst.alpha1 = mina; } else if (maxa_no01 - mina_no01 < 6) { dst.alpha0 = mina_no01; dst.alpha1 = maxa_no01; } else { float besterror = computeAlphaError(src, dst); byte besta0 = maxa; byte besta1 = mina; // Expand search space a bit. int alphaExpand = 8; mina = (byte)((mina <= alphaExpand) ? 0 : mina - alphaExpand); maxa = (byte)((maxa >= 255 - alphaExpand) ? 255 : maxa + alphaExpand); for (byte a0 = (byte)(mina + 9); a0 < maxa; a0++) { for (byte a1 = mina; a1 < a0 - 8; a1++) { dst.alpha0 = a0; dst.alpha1 = a1; float error = computeAlphaError(src, dst, besterror); if (error < besterror) { besterror = error; besta0 = a0; besta1 = a1; } } } // Try using the 6 step encoding. /*if (mina == 0 || maxa == 255)*/ { // Expand search space a bit. alphaExpand = 6; mina_no01 = (byte)((mina_no01 <= alphaExpand) ? 0 : mina_no01 - alphaExpand); maxa_no01 = (byte)((maxa_no01 >= 255 - alphaExpand) ? 255 : maxa_no01 + alphaExpand); for (byte a0 = (byte)(mina_no01 + 9); a0 < maxa_no01; a0++) { for (byte a1 = mina_no01; a1 < a0 - 8; a1++) { dst.alpha0 = a1; dst.alpha1 = a0; float error = computeAlphaError(src, dst, besterror); if (error < besterror) { besterror = error; besta0 = a1; besta1 = a0; } } } } dst.alpha0 = besta0; dst.alpha1 = besta1; } computeAlphaIndices(src, dst); }
static void computeAlphaIndices(AlphaBlock4x4 src, AlphaBlockDXT5 dst) { byte[] alphas = new byte[8]; dst.evaluatePalette(alphas, /*d3d9=*/false); // @@ Use target decoder. for (uint i = 0; i < 16; i++) { byte alpha = src.alpha[i]; uint minDist = int.MaxValue; uint bestIndex = 8; for (uint p = 0; p < 8; p++) { uint dist = alphaDistance(alpha, alphas[p]); if (dist < minDist) { minDist = dist; bestIndex = p; } } dst.setIndex(i, bestIndex); } }
/*static uint computeAlphaError8( ColorBlock & rgba, AlphaBlockDXT5 * block, int bestError = INT_MAX) { int totalError = 0; for (uint i = 0; i < 16; i++) { byte alpha = rgba.color[i].a; totalError += alphaDistance(alpha, nearestAlpha8(alpha, block.alpha0, block.alpha1)); if (totalError > bestError) { // early out return totalError; } } return totalError; }*/ static float computeAlphaError(AlphaBlock4x4 src, AlphaBlockDXT5 dst, float bestError = float.MaxValue) { byte[] alphas = new byte[8]; dst.evaluatePalette(alphas, false); // @@ Use target decoder. float totalError = 0; for (uint i = 0; i < 16; i++) { byte alpha = src.alpha[i]; uint minDist = int.MaxValue; for (uint p = 0; p < 8; p++) { uint dist = alphaDistance(alpha, alphas[p]); minDist = Math.Min(dist, minDist); } totalError += minDist * src.weights[i]; if (totalError > bestError) { // early out return totalError; } } return totalError; }
static void optimizeAlpha8(AlphaBlock4x4 src, AlphaBlockDXT5 block) { float alpha2_sum = 0; float beta2_sum = 0; float alphabeta_sum = 0; float alphax_sum = 0; float betax_sum = 0; for (uint i = 0; i < 16; i++) { uint idx = block.index(i); float alpha; if (idx < 2) { alpha = 1.0f - idx; } else { alpha = (8.0f - idx) / 7.0f; } float beta = 1 - alpha; alpha2_sum += alpha * alpha; beta2_sum += beta * beta; alphabeta_sum += alpha * beta; alphax_sum += alpha * src.alpha[i]; betax_sum += beta * src.alpha[i]; } float factor = 1.0f / (alpha2_sum * beta2_sum - alphabeta_sum * alphabeta_sum); float a = (alphax_sum * beta2_sum - betax_sum * alphabeta_sum) * factor; float b = (betax_sum * alpha2_sum - alphax_sum * alphabeta_sum) * factor; byte alpha0 = (byte)(Math.Min(Math.Max(a, 0.0f), 255.0f)); byte alpha1 = (byte)(Math.Min(Math.Max(b, 0.0f), 255.0f)); if (alpha0 < alpha1) { swap(ref alpha0, ref alpha1); // Flip indices: for (uint i = 0; i < 16; i++) { uint idx = block.index(i); if (idx < 2) { block.setIndex(i, 1 - idx); } else { block.setIndex(i, 9 - idx); } } } else if (alpha0 == alpha1) { for (uint i = 0; i < 16; i++) { block.setIndex(i, 0); } } block.alpha0 = alpha0; block.alpha1 = alpha1; }