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); } }
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 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; }
// maxColor and minColor are expected to be in the same range as the color set. static uint computeIndices4(ColorSet set, Vector3 maxColor, Vector3 minColor) { Vector3[] palette = new Vector3[4]; palette[0] = maxColor; palette[1] = minColor; palette[2] = Vector3.Lerp(palette[0], palette[1], 1.0f / 3.0f); palette[3] = Vector3.Lerp(palette[0], palette[1], 2.0f / 3.0f); Vector3[] row0 = new Vector3[6]; Vector3[] row1 = new Vector3[6]; uint indices = 0; //for(int i = 0; i < 16; i++) for (uint y = 0; y < 4; y++) { for (uint x = 0; x < 4; x++) { uint i = y * 4 + x; if (!set.isValidIndex(i)) { // Skip masked pixels and out of bounds. continue; } Vector3 color = new Vector3(set.color[i].x, set.color[i].y, set.color[i].z); // Add error. color += row0[1 + x]; float d0 = colorDistance(palette[0], color); float d1 = colorDistance(palette[1], color); float d2 = colorDistance(palette[2], color); float d3 = colorDistance(palette[3], color); uint b0 = d0 > d3?(uint)1:(uint)0; uint b1 = d1 > d2?(uint)1:(uint)0; uint b2 = d0 > d2?(uint)1:(uint)0; uint b3 = d1 > d3?(uint)1:(uint)0; uint b4 = d2 > d3?(uint)1:(uint)0; uint x0 = b1 & b2; uint x1 = b0 & b3; uint x2 = b0 & b4; uint index = x2 | ((x0 | x1) << 1); indices |= index << (int)(2 * i); // Compute new error. Vector3 diff = color - palette[index]; // Propagate new error. //row0[1+x+1] += 7.0f / 16.0f * diff; //row1[1+x-1] += 3.0f / 16.0f * diff; //row1[1+x+0] += 5.0f / 16.0f * diff; //row1[1+x+1] += 1.0f / 16.0f * diff; } swap(ref row0, ref row1); row1 = new Vector3[6]; } return(indices); }