private static void Encodedxtcolorblockfaster(GLubyte *blkaddr, GLubyte ***srccolors, GLint numxpixels, GLint numypixels, GLuint type) { GLubyte **bestcolor = stackalloc GLubyte *[2]; GLubyte **basecolors = stackalloc GLubyte *[2]; var bc1 = stackalloc GLubyte[3]; var bc2 = stackalloc GLubyte[3]; basecolors[0] = bc1; basecolors[1] = bc2; GLubyte i, j; GLuint highcv; var haveAlpha = GlFalse; var lowcv = highcv = (uint)(srccolors[0][0][0] * srccolors[0][0][0] * Redweight + srccolors[0][0][1] * srccolors[0][0][1] * Greenweight + srccolors[0][0][2] * srccolors[0][0][2] * Blueweight); bestcolor[0] = bestcolor[1] = srccolors[0][0]; for (j = 0; j < numypixels; j++) { for (i = 0; i < numxpixels; i++) { if ((type != GlCompressedRgbaS3TcDxt1Ext) || (srccolors[j][i][3] <= Alphacut)) { var testcv = (uint)(srccolors[j][i][0] * srccolors[j][i][0] * Redweight + srccolors[j][i][1] * srccolors[j][i][1] * Greenweight + srccolors[j][i][2] * srccolors[j][i][2] * Blueweight); if (testcv > highcv) { highcv = testcv; bestcolor[1] = srccolors[j][i]; } else if (testcv < lowcv) { lowcv = testcv; bestcolor[0] = srccolors[j][i]; } } else { haveAlpha = GlTrue; } } } for (j = 0; j < 2; j++) { for (i = 0; i < 3; i++) { basecolors[j][i] = bestcolor[j][i]; } } bestcolor[0] = basecolors[0]; bestcolor[1] = basecolors[1]; Fancybasecolorsearch(srccolors, bestcolor, numxpixels, numypixels); Storedxtencodedblock(blkaddr, srccolors, bestcolor, numxpixels, numypixels, type, haveAlpha); }
// ReSharper disable once FunctionComplexityOverflow private static void Fancybasecolorsearch(GLubyte ***srccolors, GLubyte **bestcolor, GLint numxpixels, GLint numypixels) { GLint i, j; GLint * blockerrlin0 = stackalloc GLint[3]; GLint * blockerrlin1 = stackalloc GLint[3]; GLint **blockerrlin = stackalloc GLint *[2]; blockerrlin[0] = blockerrlin0; blockerrlin[1] = blockerrlin1; GLubyte * nrcolor = stackalloc GLubyte[2]; GLint * pixerrorcolorbest = stackalloc GLint[3]; GLubyte enc = 0; GLubyte **cv = stackalloc GLubyte *[4]; GLubyte * cv0 = stackalloc GLubyte[4]; GLubyte * cv1 = stackalloc GLubyte[4]; GLubyte * cv2 = stackalloc GLubyte[4]; GLubyte * cv3 = stackalloc GLubyte[4]; cv[0] = cv0; cv[1] = cv1; cv[2] = cv2; cv[3] = cv3; GLubyte **testcolor = stackalloc GLubyte *[2]; GLubyte * tc0 = stackalloc GLubyte[3]; GLubyte * tc1 = stackalloc GLubyte[3]; testcolor[0] = tc0; testcolor[1] = tc1; if (((bestcolor[0][0] & 0xf8) << 8 | (bestcolor[0][1] & 0xfc) << 3 | bestcolor[0][2] >> 3) < ((bestcolor[1][0] & 0xf8) << 8 | (bestcolor[1][1] & 0xfc) << 3 | bestcolor[1][2] >> 3)) { testcolor[0][0] = bestcolor[0][0]; testcolor[0][1] = bestcolor[0][1]; testcolor[0][2] = bestcolor[0][2]; testcolor[1][0] = bestcolor[1][0]; testcolor[1][1] = bestcolor[1][1]; testcolor[1][2] = bestcolor[1][2]; } else { testcolor[1][0] = bestcolor[0][0]; testcolor[1][1] = bestcolor[0][1]; testcolor[1][2] = bestcolor[0][2]; testcolor[0][0] = bestcolor[1][0]; testcolor[0][1] = bestcolor[1][1]; testcolor[0][2] = bestcolor[1][2]; } for (i = 0; i < 3; i++) { cv[0][i] = testcolor[0][i]; cv[1][i] = testcolor[1][i]; cv[2][i] = (byte)((testcolor[0][i] * 2 + testcolor[1][i]) / 3); cv[3][i] = (byte)((testcolor[0][i] + testcolor[1][i] * 2) / 3); } blockerrlin[0][0] = 0; blockerrlin[0][1] = 0; blockerrlin[0][2] = 0; blockerrlin[1][0] = 0; blockerrlin[1][1] = 0; blockerrlin[1][2] = 0; nrcolor[0] = 0; nrcolor[1] = 0; for (j = 0; j < numypixels; j++) { for (i = 0; i < numxpixels; i++) { var pixerrorbest = 0xffffffff; GLint colors; for (colors = 0; colors < 4; colors++) { var colordist = srccolors[j][i][0] - (cv[colors][0]); var pixerror = (uint)(colordist * colordist * Redweight); var pixerrorred = (uint)colordist; colordist = srccolors[j][i][1] - (cv[colors][1]); pixerror += (uint)(colordist * colordist * Greenweight); var pixerrorgreen = (uint)colordist; colordist = srccolors[j][i][2] - (cv[colors][2]); pixerror += (uint)(colordist * colordist * Blueweight); var pixerrorblue = (uint)colordist; if (pixerror < pixerrorbest) { enc = (byte)colors; pixerrorbest = pixerror; pixerrorcolorbest[0] = (int)pixerrorred; pixerrorcolorbest[1] = (int)pixerrorgreen; pixerrorcolorbest[2] = (int)pixerrorblue; } } GLint z; if (enc == 0) { for (z = 0; z < 3; z++) { blockerrlin[0][z] += 3 * pixerrorcolorbest[z]; } nrcolor[0] += 3; } else if (enc == 2) { for (z = 0; z < 3; z++) { blockerrlin[0][z] += 2 * pixerrorcolorbest[z]; } nrcolor[0] += 2; for (z = 0; z < 3; z++) { blockerrlin[1][z] += 1 * pixerrorcolorbest[z]; } nrcolor[1] += 1; } else if (enc == 3) { for (z = 0; z < 3; z++) { blockerrlin[0][z] += 1 * pixerrorcolorbest[z]; } nrcolor[0] += 1; for (z = 0; z < 3; z++) { blockerrlin[1][z] += 2 * pixerrorcolorbest[z]; } nrcolor[1] += 2; } else if (enc == 1) { for (z = 0; z < 3; z++) { blockerrlin[1][z] += 3 * pixerrorcolorbest[z]; } nrcolor[1] += 3; } } } if (nrcolor[0] == 0) { nrcolor[0] = 1; } if (nrcolor[1] == 0) { nrcolor[1] = 1; } for (j = 0; j < 2; j++) { for (i = 0; i < 3; i++) { var newvalue = testcolor[j][i] + blockerrlin[j][i] / nrcolor[j]; if (newvalue <= 0) { testcolor[j][i] = 0; } else if (newvalue >= 255) { testcolor[j][i] = 255; } else { testcolor[j][i] = (byte)newvalue; } } } if ((Math.Abs(testcolor[0][0] - testcolor[1][0]) < 8) && (Math.Abs(testcolor[0][1] - testcolor[1][1]) < 4) && (Math.Abs(testcolor[0][2] - testcolor[1][2]) < 8)) { var coldiffred = (byte)Math.Abs(testcolor[0][0] - testcolor[1][0]); var coldiffgreen = (byte)(2 * Math.Abs(testcolor[0][1] - testcolor[1][1])); var coldiffblue = (byte)Math.Abs(testcolor[0][2] - testcolor[1][2]); var coldiffmax = coldiffred; if (coldiffmax < coldiffgreen) { coldiffmax = coldiffgreen; } if (coldiffmax < coldiffblue) { coldiffmax = coldiffblue; } if (coldiffmax > 0) { GLubyte factor; if (coldiffmax > 4) { factor = 2; } else if (coldiffmax > 2) { factor = 3; } else { factor = 4; } GLubyte ind0; GLubyte ind1; if (testcolor[1][1] >= testcolor[0][1]) { ind1 = 1; ind0 = 0; } else { ind1 = 0; ind0 = 1; } if ((testcolor[ind1][1] + factor * coldiffgreen) <= 255) { testcolor[ind1][1] += (byte)(factor * coldiffgreen); } else { testcolor[ind1][1] = 255; } if ((testcolor[ind1][0] - testcolor[ind0][1]) > 0) { if ((testcolor[ind1][0] + factor * coldiffred) <= 255) { testcolor[ind1][0] += (byte)(factor * coldiffred); } else { testcolor[ind1][0] = 255; } } else { if ((testcolor[ind0][0] + factor * coldiffred) <= 255) { testcolor[ind0][0] += (byte)(factor * coldiffred); } else { testcolor[ind0][0] = 255; } } if ((testcolor[ind1][2] - testcolor[ind0][2]) > 0) { if ((testcolor[ind1][2] + factor * coldiffblue) <= 255) { testcolor[ind1][2] += (byte)(factor * coldiffblue); } else { testcolor[ind1][2] = 255; } } else { if ((testcolor[ind0][2] + factor * coldiffblue) <= 255) { testcolor[ind0][2] += (byte)(factor * coldiffblue); } else { testcolor[ind0][2] = 255; } } } } if (((testcolor[0][0] & 0xf8) << 8 | (testcolor[0][1] & 0xfc) << 3 | testcolor[0][2] >> 3) < ((testcolor[1][0] & 0xf8) << 8 | (testcolor[1][1] & 0xfc) << 3 | testcolor[1][2]) >> 3) { for (i = 0; i < 3; i++) { bestcolor[0][i] = testcolor[0][i]; bestcolor[1][i] = testcolor[1][i]; } } else { for (i = 0; i < 3; i++) { bestcolor[0][i] = testcolor[1][i]; bestcolor[1][i] = testcolor[0][i]; } } }
// ReSharper disable once FunctionComplexityOverflow public static void CompressDxtn(GLint width, GLint height, GLubyte *srcPixData, GLenum destFormat, GLubyte *dest, GLint dstRowStride) { const int srccomps = 4; GLubyte * blkaddr = dest; GLubyte ***srcpixels = stackalloc GLubyte * *[4]; GLubyte ** scpp0 = stackalloc GLubyte *[4]; GLubyte * scp0 = stackalloc GLubyte[4]; GLubyte * scp1 = stackalloc GLubyte[4]; GLubyte * scp2 = stackalloc GLubyte[4]; GLubyte * scp3 = stackalloc GLubyte[4]; scpp0[0] = scp0; scpp0[1] = scp1; scpp0[2] = scp2; scpp0[3] = scp3; GLubyte **scpp1 = stackalloc GLubyte *[4]; GLubyte * scp10 = stackalloc GLubyte[4]; GLubyte * scp11 = stackalloc GLubyte[4]; GLubyte * scp12 = stackalloc GLubyte[4]; GLubyte * scp13 = stackalloc GLubyte[4]; scpp1[0] = scp10; scpp1[1] = scp11; scpp1[2] = scp12; scpp1[3] = scp13; GLubyte **scpp2 = stackalloc GLubyte *[4]; GLubyte * scp20 = stackalloc GLubyte[4]; GLubyte * scp21 = stackalloc GLubyte[4]; GLubyte * scp22 = stackalloc GLubyte[4]; GLubyte * scp23 = stackalloc GLubyte[4]; scpp2[0] = scp20; scpp2[1] = scp21; scpp2[2] = scp22; scpp2[3] = scp23; GLubyte **scpp3 = stackalloc GLubyte *[4]; GLubyte * scp30 = stackalloc GLubyte[4]; GLubyte * scp31 = stackalloc GLubyte[4]; GLubyte * scp32 = stackalloc GLubyte[4]; GLubyte * scp33 = stackalloc GLubyte[4]; scpp3[0] = scp30; scpp3[1] = scp31; scpp3[2] = scp32; scpp3[3] = scp33; srcpixels[0] = scpp0; srcpixels[1] = scpp1; srcpixels[2] = scpp2; srcpixels[3] = scpp3; GLchan *srcaddr; GLint numxpixels, numypixels; GLint i, j; GLint dstRowDiff; switch (destFormat) { case GlCompressedRgbS3TcDxt1Ext: case GlCompressedRgbaS3TcDxt1Ext: dstRowDiff = dstRowStride >= (width * 2) ? dstRowStride - (((width + 3) & ~3) * 2) : 0; for (j = 0; j < height; j += 4) { if (height > j + 3) { numypixels = 4; } else { numypixels = height - j; } srcaddr = srcPixData + j * width * srccomps; for (i = 0; i < width; i += 4) { if (width > i + 3) { numxpixels = 4; } else { numxpixels = width - i; } Extractsrccolors(srcpixels, srcaddr, width, numxpixels, numypixels, srccomps); Encodedxtcolorblockfaster(blkaddr, srcpixels, numxpixels, numypixels, destFormat); srcaddr += srccomps * numxpixels; blkaddr += 8; } blkaddr += dstRowDiff; } break; case GlCompressedRgbaS3TcDxt3Ext: dstRowDiff = dstRowStride >= (width * 4) ? dstRowStride - (((width + 3) & ~3) * 4) : 0; for (j = 0; j < height; j += 4) { if (height > j + 3) { numypixels = 4; } else { numypixels = height - j; } srcaddr = srcPixData + j * width * srccomps; for (i = 0; i < width; i += 4) { if (width > i + 3) { numxpixels = 4; } else { numxpixels = width - i; } Extractsrccolors(srcpixels, srcaddr, width, numxpixels, numypixels, srccomps); *blkaddr++ = (byte)((srcpixels[0][0][3] >> 4) | (srcpixels[0][1][3] & 0xf0)); *blkaddr++ = (byte)((srcpixels[0][2][3] >> 4) | (srcpixels[0][3][3] & 0xf0)); *blkaddr++ = (byte)((srcpixels[1][0][3] >> 4) | (srcpixels[1][1][3] & 0xf0)); *blkaddr++ = (byte)((srcpixels[1][2][3] >> 4) | (srcpixels[1][3][3] & 0xf0)); *blkaddr++ = (byte)((srcpixels[2][0][3] >> 4) | (srcpixels[2][1][3] & 0xf0)); *blkaddr++ = (byte)((srcpixels[2][2][3] >> 4) | (srcpixels[2][3][3] & 0xf0)); *blkaddr++ = (byte)((srcpixels[3][0][3] >> 4) | (srcpixels[3][1][3] & 0xf0)); *blkaddr++ = (byte)((srcpixels[3][2][3] >> 4) | (srcpixels[3][3][3] & 0xf0)); Encodedxtcolorblockfaster(blkaddr, srcpixels, numxpixels, numypixels, destFormat); srcaddr += srccomps * numxpixels; blkaddr += 8; } blkaddr += dstRowDiff; } break; case GlCompressedRgbaS3TcDxt5Ext: dstRowDiff = dstRowStride >= (width * 4) ? dstRowStride - (((width + 3) & ~3) * 4) : 0; for (j = 0; j < height; j += 4) { if (height > j + 3) { numypixels = 4; } else { numypixels = height - j; } srcaddr = srcPixData + j * width * srccomps; for (i = 0; i < width; i += 4) { if (width > i + 3) { numxpixels = 4; } else { numxpixels = width - i; } Extractsrccolors(srcpixels, srcaddr, width, numxpixels, numypixels, srccomps); Encodedxt5Alpha(blkaddr, srcpixels, numxpixels, numypixels); Encodedxtcolorblockfaster(blkaddr + 8, srcpixels, numxpixels, numypixels, destFormat); srcaddr += srccomps * numxpixels; blkaddr += 16; } blkaddr += dstRowDiff; } break; default: throw new ArgumentException(string.Format("libdxtn: Bad dstFormat {0} in tx_compress_dxtn\n", destFormat)); } }
private static void Storedxtencodedblock(GLubyte *blkaddr, GLubyte ***srccolors, GLubyte **bestcolor, GLint numxpixels, GLint numypixels, GLuint type, GLboolean haveAlpha) { GLint i, j, colors; GLuint pixerror, pixerrorbest; GLint colordist; GLuint bits = 0, bits2 = 0; GLubyte enc = 0; GLubyte **cv = stackalloc GLubyte *[4]; GLubyte * cv0 = stackalloc GLubyte[4]; GLubyte * cv1 = stackalloc GLubyte[4]; GLubyte * cv2 = stackalloc GLubyte[4]; GLubyte * cv3 = stackalloc GLubyte[4]; cv[0] = cv0; cv[1] = cv1; cv[2] = cv2; cv[3] = cv3; bestcolor[0][0] = (byte)(bestcolor[0][0] & 0xf8); bestcolor[0][1] = (byte)(bestcolor[0][1] & 0xfc); bestcolor[0][2] = (byte)(bestcolor[0][2] & 0xf8); bestcolor[1][0] = (byte)(bestcolor[1][0] & 0xf8); bestcolor[1][1] = (byte)(bestcolor[1][1] & 0xfc); bestcolor[1][2] = (byte)(bestcolor[1][2] & 0xf8); var color0 = (ushort)(bestcolor[0][0] << 8 | bestcolor[0][1] << 3 | bestcolor[0][2] >> 3); var color1 = (ushort)(bestcolor[1][0] << 8 | bestcolor[1][1] << 3 | bestcolor[1][2] >> 3); if (color0 < color1) { var tempcolor = color0; color0 = color1; color1 = tempcolor; var colorptr = bestcolor[0]; bestcolor[0] = bestcolor[1]; bestcolor[1] = colorptr; } for (i = 0; i < 3; i++) { cv[0][i] = bestcolor[0][i]; cv[1][i] = bestcolor[1][i]; cv[2][i] = (byte)((bestcolor[0][i] * 2 + bestcolor[1][i]) / 3); cv[3][i] = (byte)((bestcolor[0][i] + bestcolor[1][i] * 2) / 3); } uint testerror = 0; for (j = 0; j < numypixels; j++) { for (i = 0; i < numxpixels; i++) { pixerrorbest = 0xffffffff; for (colors = 0; colors < 4; colors++) { colordist = srccolors[j][i][0] - cv[colors][0]; pixerror = (uint)(colordist * colordist * Redweight); colordist = (srccolors[j][i][1] - cv[colors][1]); pixerror += (uint)(colordist * colordist * Greenweight); colordist = srccolors[j][i][2] - cv[colors][2]; pixerror += (uint)(colordist * colordist * Blueweight); if (pixerror < pixerrorbest) { pixerrorbest = pixerror; enc = (byte)colors; } } testerror += pixerrorbest; bits |= (uint)(enc << (2 * (j * 4 + i))); } } for (i = 0; i < 3; i++) { cv[2][i] = (byte)((bestcolor[0][i] + bestcolor[1][i]) / 2); /* this isn't used. Looks like the black color constant can only be used * with RGB_DXT1 if I read the spec correctly (note though that the radeon gpu disagrees, * it will decode 3 to black even with DXT3/5), and due to how the color searching works * it won't get used even then */ cv[3][i] = 0; } uint testerror2 = 0; for (j = 0; j < numypixels; j++) { for (i = 0; i < numxpixels; i++) { pixerrorbest = 0xffffffff; if ((type == GlCompressedRgbaS3TcDxt1Ext) && (srccolors[j][i][3] <= Alphacut)) { enc = 3; pixerrorbest = 0; /* don't calculate error */ } else { /* we're calculating the same what we have done already for colors 0-1 above... */ for (colors = 0; colors < 3; colors++) { colordist = srccolors[j][i][0] - cv[colors][0]; pixerror = (uint)(colordist * colordist * Redweight); colordist = srccolors[j][i][1] - cv[colors][1]; pixerror += (uint)(colordist * colordist * Greenweight); colordist = srccolors[j][i][2] - cv[colors][2]; pixerror += (uint)(colordist * colordist * Blueweight); if (pixerror < pixerrorbest) { pixerrorbest = pixerror; /* need to exchange colors later */ if (colors > 1) { enc = (byte)colors; } else { enc = (byte)(colors ^ 1); } } } } testerror2 += pixerrorbest; bits2 |= (uint)(enc << (2 * (j * 4 + i))); } } /* finally we're finished, write back colors and bits */ if ((testerror > testerror2) || (haveAlpha != GlFalse)) { *blkaddr++ = (byte)(color1 & 0xff); *blkaddr++ = (byte)(color1 >> 8); *blkaddr++ = (byte)(color0 & 0xff); *blkaddr++ = (byte)(color0 >> 8); *blkaddr++ = (byte)(bits2 & 0xff); *blkaddr++ = (byte)((bits2 >> 8) & 0xff); *blkaddr++ = (byte)((bits2 >> 16) & 0xff); *blkaddr = (byte)(bits2 >> 24); } else { *blkaddr++ = (byte)(color0 & 0xff); *blkaddr++ = (byte)(color0 >> 8); *blkaddr++ = (byte)(color1 & 0xff); *blkaddr++ = (byte)(color1 >> 8); *blkaddr++ = (byte)(bits & 0xff); *blkaddr++ = (byte)((bits >> 8) & 0xff); *blkaddr++ = (byte)((bits >> 16) & 0xff); *blkaddr = (byte)(bits >> 24); } }