/// <summary> /// Builds a 4-color color table for a DXT1-compressed 4x4 block of texels and then decodes the texels. /// </summary> /// <remarks>See https://msdn.microsoft.com/en-us/library/windows/desktop/bb694531(v=vs.85).aspx#BC1 </remarks> static Color32[] DecodeDXT1TexelBlock(UnityBinaryReader r, bool containsAlpha) { // Create the color table. var colorTable = new Color[4]; colorTable[0] = ColorEx.B565ToColor(r.ReadLEUInt16()); colorTable[1] = ColorEx.B565ToColor(r.ReadLEUInt16()); if (!containsAlpha) { colorTable[2] = Color.Lerp(colorTable[0], colorTable[1], 1.0f / 3); colorTable[3] = Color.Lerp(colorTable[0], colorTable[1], 2.0f / 3); } else { colorTable[2] = Color.Lerp(colorTable[0], colorTable[1], 1.0f / 2); colorTable[3] = new Color(0, 0, 0, 0); } // Calculate pixel colors. return(DecodeDXT1TexelBlock(r, colorTable)); }
/// <summary> /// Decodes a DXT3-compressed 4x4 block of texels. /// </summary> /// <remarks>See https://msdn.microsoft.com/en-us/library/windows/desktop/bb694531(v=vs.85).aspx#BC2 </remarks> static Color32[] DecodeDXT3TexelBlock(UnityBinaryReader r) { // Read compressed pixel alphas. var compressedAlphas = new byte[16]; for (var rowIndex = 0; rowIndex < 4; rowIndex++) { var compressedAlphaRow = r.ReadLEUInt16(); for (var columnIndex = 0; columnIndex < 4; columnIndex++) { // Each compressed alpha is 4 bits. compressedAlphas[(4 * rowIndex) + columnIndex] = (byte)((compressedAlphaRow >> (columnIndex * 4)) & 0xF); } } // Calculate pixel alphas. var alphas = new byte[16]; for (var i = 0; i < 16; i++) { var alphaPercent = (float)compressedAlphas[i] / 15; alphas[i] = (byte)Mathf.RoundToInt(alphaPercent * 255); } // Create the color table. var colorTable = new Color[4]; colorTable[0] = ColorEx.B565ToColor(r.ReadLEUInt16()); colorTable[1] = ColorEx.B565ToColor(r.ReadLEUInt16()); colorTable[2] = Color.Lerp(colorTable[0], colorTable[1], 1.0f / 3); colorTable[3] = Color.Lerp(colorTable[0], colorTable[1], 2.0f / 3); // Calculate pixel colors. var colors = DecodeDXT1TexelBlock(r, colorTable); for (var i = 0; i < 16; i++) { colors[i].a = alphas[i]; } return(colors); }
/// <summary> /// Decodes a DXT5-compressed 4x4 block of texels. /// </summary> /// <remarks>See https://msdn.microsoft.com/en-us/library/windows/desktop/bb694531(v=vs.85).aspx#BC3 </remarks> static Color32[] DecodeDXT5TexelBlock(UnityBinaryReader r) { // Create the alpha table. var alphaTable = new float[8]; alphaTable[0] = r.ReadByte(); alphaTable[1] = r.ReadByte(); if (alphaTable[0] > alphaTable[1]) { for (var i = 0; i < 6; i++) { alphaTable[2 + i] = Mathf.Lerp(alphaTable[0], alphaTable[1], (float)(1 + i) / 7); } } else { for (var i = 0; i < 4; i++) { alphaTable[2 + i] = Mathf.Lerp(alphaTable[0], alphaTable[1], (float)(1 + i) / 5); } alphaTable[6] = 0; alphaTable[7] = 255; } // Read pixel alpha indices. var alphaIndices = new uint[16]; var alphaIndexBytesRow0 = new byte[3]; r.Read(alphaIndexBytesRow0, 0, alphaIndexBytesRow0.Length); Array.Reverse(alphaIndexBytesRow0); // Take care of little-endianness. var alphaIndexBytesRow1 = new byte[3]; r.Read(alphaIndexBytesRow1, 0, alphaIndexBytesRow1.Length); Array.Reverse(alphaIndexBytesRow1); // Take care of little-endianness. const uint bitsPerAlphaIndex = 3; alphaIndices[0] = (uint)Utils.GetBits(21, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[1] = (uint)Utils.GetBits(18, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[2] = (uint)Utils.GetBits(15, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[3] = (uint)Utils.GetBits(12, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[4] = (uint)Utils.GetBits(9, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[5] = (uint)Utils.GetBits(6, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[6] = (uint)Utils.GetBits(3, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[7] = (uint)Utils.GetBits(0, bitsPerAlphaIndex, alphaIndexBytesRow0); alphaIndices[8] = (uint)Utils.GetBits(21, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[9] = (uint)Utils.GetBits(18, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[10] = (uint)Utils.GetBits(15, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[11] = (uint)Utils.GetBits(12, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[12] = (uint)Utils.GetBits(9, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[13] = (uint)Utils.GetBits(6, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[14] = (uint)Utils.GetBits(3, bitsPerAlphaIndex, alphaIndexBytesRow1); alphaIndices[15] = (uint)Utils.GetBits(0, bitsPerAlphaIndex, alphaIndexBytesRow1); // Create the color table. var colorTable = new Color[4]; colorTable[0] = ColorEx.B565ToColor(r.ReadLEUInt16()); colorTable[1] = ColorEx.B565ToColor(r.ReadLEUInt16()); colorTable[2] = Color.Lerp(colorTable[0], colorTable[1], 1.0f / 3); colorTable[3] = Color.Lerp(colorTable[0], colorTable[1], 2.0f / 3); // Calculate pixel colors. var colors = DecodeDXT1TexelBlock(r, colorTable); for (var i = 0; i < 16; i++) { colors[i].a = (byte)Mathf.Round(alphaTable[alphaIndices[i]]); } return(colors); }