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 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); }
void compressDXT5A(ColorBlock src, AlphaBlockDXT5 dst) { AlphaBlock4x4 tmp = new AlphaBlock4x4(); tmp.init(src, 3); compressDXT5A(tmp, dst); }
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 float computeAlphaError_RGBM(ColorSet src, ColorBlock RGB, AlphaBlockDXT5 dst, float bestError = float.MaxValue) { byte[] alphas = new byte[8]; dst.evaluatePalette(alphas, /*d3d9=*/ false); // @@ Use target decoder. float totalError = 0; for (uint i = 0; i < 16; i++) { float R = src.color[i].x; float G = src.color[i].y; float B = src.color[i].z; float r = (float)(RGB.color[i].r) / 255.0f; float g = (float)(RGB.color[i].g) / 255.0f; float b = (float)(RGB.color[i].b) / 255.0f; float minDist = float.MaxValue; for (uint p = 0; p < 8; p++) { // Compute M. float M = (float)(alphas[p]) / 255.0f * (1 - threshold) + threshold; // Decode color. float fr = r * M; float fg = g * M; float fb = b * M; // Measure error. float error = Mathf.Pow(R - fr, 2) + Mathf.Pow(G - fg, 2) + Mathf.Pow(B - fb, 2); minDist = Mathf.Min(error, minDist); } totalError += minDist * src.weights[i]; if (totalError > bestError) { // early out return(totalError); } } return(totalError); }
static void computeAlphaIndices_RGBM(ColorSet src, ColorBlock RGB, AlphaBlockDXT5 dst) { byte[] alphas = new byte[8]; dst.evaluatePalette(alphas, /*d3d9=*/ false); // @@ Use target decoder. for (uint i = 0; i < 16; i++) { float R = src.color[i].x; float G = src.color[i].y; float B = src.color[i].z; float r = (float)(RGB.color[i].r) / 255.0f; float g = (float)(RGB.color[i].g) / 255.0f; float b = (float)(RGB.color[i].b) / 255.0f; float minDist = float.MaxValue; uint bestIndex = 8; for (uint p = 0; p < 8; p++) { // Compute M. float M = (float)(alphas[p]) / 255.0f * (1 - threshold) + threshold; // Decode color. float fr = r * M; float fg = g * M; float fb = b * M; // Measure error. float error = Mathf.Pow(R - fr, 2) + Mathf.Pow(G - fg, 2) + Mathf.Pow(B - fb, 2); if (error < minDist) { minDist = error; bestIndex = p; } } dst.setIndex(i, bestIndex); } }
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_RGBM(ColorSet src, ColorBlock RGB, 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 = min(mina, alpha); maxa = max(maxa, alpha); if (alpha != 0 && alpha != 255) { mina_no01 = min(mina_no01, alpha); maxa_no01 = max(maxa_no01, alpha); } }*/ mina = 0; maxa = 255; mina_no01 = 0; maxa_no01 = 255; /*if (maxa - mina < 8) { dst.alpha0 = maxa; dst.alpha1 = mina; nvDebugCheck(computeAlphaError(src, dst) == 0); } else if (maxa_no01 - mina_no01 < 6) { dst.alpha0 = mina_no01; dst.alpha1 = maxa_no01; nvDebugCheck(computeAlphaError(src, dst) == 0); } else*/ { float besterror = computeAlphaError_RGBM(src, RGB, 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_RGBM(src, RGB, 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_RGBM(src, RGB, dst, besterror); if (error < besterror) { besterror = error; besta0 = a1; besta1 = a0; } } } } dst.alpha0 = besta0; dst.alpha1 = besta1; } computeAlphaIndices_RGBM(src, RGB, dst); }
static void computeAlphaIndices_RGBM(ColorSet src, ColorBlock RGB, AlphaBlockDXT5 dst) { byte[] alphas = new byte[8]; dst.evaluatePalette(alphas, /*d3d9=*/false); // @@ Use target decoder. for (uint i = 0; i < 16; i++) { float R = src.color[i].x; float G = src.color[i].y; float B = src.color[i].z; float r = (float)(RGB.color[i].r) / 255.0f; float g = (float)(RGB.color[i].g) / 255.0f; float b = (float)(RGB.color[i].b) / 255.0f; float minDist = float.MaxValue; uint bestIndex = 8; for (uint p = 0; p < 8; p++) { // Compute M. float M = (float)(alphas[p]) / 255.0f * (1 - threshold) + threshold; // Decode color. float fr = r * M; float fg = g * M; float fb = b * M; // Measure error. float error = Mathf.Pow(R - fr, 2) + Mathf.Pow(G - fg, 2) + Mathf.Pow(B - fb, 2); if (error < minDist) { minDist = error; bestIndex = p; } } dst.setIndex(i, bestIndex); } }
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 float computeAlphaError_RGBM(ColorSet src, ColorBlock RGB, AlphaBlockDXT5 dst, float bestError = float.MaxValue) { byte[] alphas = new byte[8]; dst.evaluatePalette(alphas, /*d3d9=*/false); // @@ Use target decoder. float totalError = 0; for (uint i = 0; i < 16; i++) { float R = src.color[i].x; float G = src.color[i].y; float B = src.color[i].z; float r = (float)(RGB.color[i].r) / 255.0f; float g = (float)(RGB.color[i].g) / 255.0f; float b = (float)(RGB.color[i].b) / 255.0f; float minDist = float.MaxValue; for (uint p = 0; p < 8; p++) { // Compute M. float M = (float)(alphas[p]) / 255.0f * (1 - threshold) + threshold; // Decode color. float fr = r * M; float fg = g * M; float fb = b * M; // Measure error. float error = Mathf.Pow(R - fr, 2) + Mathf.Pow(G - fg, 2) + Mathf.Pow(B - fb, 2); minDist = Mathf.Min(error, minDist); } totalError += minDist * src.weights[i]; if (totalError > bestError) { // early out return totalError; } } return totalError; }
/*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; }
void compressDXT5A_RGBM(ColorSet src, ColorBlock RGB, 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 = min(mina, alpha); * maxa = max(maxa, alpha); * * if (alpha != 0 && alpha != 255) { * mina_no01 = min(mina_no01, alpha); * maxa_no01 = max(maxa_no01, alpha); * } * }*/ mina = 0; maxa = 255; mina_no01 = 0; maxa_no01 = 255; /*if (maxa - mina < 8) { * dst.alpha0 = maxa; * dst.alpha1 = mina; * * nvDebugCheck(computeAlphaError(src, dst) == 0); * } * else if (maxa_no01 - mina_no01 < 6) { * dst.alpha0 = mina_no01; * dst.alpha1 = maxa_no01; * * nvDebugCheck(computeAlphaError(src, dst) == 0); * } * else*/ { float besterror = computeAlphaError_RGBM(src, RGB, 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_RGBM(src, RGB, 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_RGBM(src, RGB, dst, besterror); if (error < besterror) { besterror = error; besta0 = a1; besta1 = a0; } } } } dst.alpha0 = besta0; dst.alpha1 = besta1; } computeAlphaIndices_RGBM(src, RGB, dst); }
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; }
/* * static void optimizeAlpha6( ColorBlock & rgba, AlphaBlockDXT5 * block) * { * float alpha2_sum = 0; * float beta2_sum = 0; * float alphabeta_sum = 0; * float alphax_sum = 0; * float betax_sum = 0; * * for (int i = 0; i < 16; i++) * { * byte x = rgba.color[i].a; * if (x == 0 || x == 255) continue; * * uint bits = block.index(i); * if (bits == 6 || bits == 7) continue; * * float alpha; * if (bits == 0) alpha = 1.0f; * else if (bits == 1) alpha = 0.0f; * else alpha = (6.0f - block.index(i)) / 5.0f; * * float beta = 1 - alpha; * * alpha2_sum += alpha * alpha; * beta2_sum += beta * beta; * alphabeta_sum += alpha * beta; * alphax_sum += alpha * x; * betax_sum += beta * x; * } * * 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; * * uint alpha0 = uint(min(max(a, 0.0f), 255.0f)); * uint alpha1 = uint(min(max(b, 0.0f), 255.0f)); * * if (alpha0 > alpha1) * { * swap(alpha0, alpha1); * } * * block.alpha0 = alpha0; * block.alpha1 = alpha1; * } */ static bool sameIndices(AlphaBlockDXT5 block0, AlphaBlockDXT5 block1) { ulong mask = ~(ulong)(0xFFFF); return((block0.u | mask) == (block1.u | mask)); }
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); }