// Please note, everything below this // point was originally available here: // http://www.modthesims.info/showthread.php?t=361153 // // // The source has been modified for use in this library. // // This disclaimer was last // modified on August 9, 2011. using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; using System.Runtime.InteropServices; using System.Text; namespace SaveGameEditor { public static class DDS { private static byte[] Expand5 = new byte[0x20]; private static byte[] Expand6 = new byte[0x40]; private static int nIterPower = 4; private static byte[,] OMatch5 = new byte[0x100, 2]; private static byte[,] OMatch6 = new byte[0x100, 2]; private static readonly int[] prods = new int[] { 0x90000, 0x900, 0x40102, 0x10402 }; private static byte[] QuantGTab = new byte[0x110]; private static byte[] QuantRBTab = new byte[0x110]; private static bool sInitted; private static readonly int[] w1Tab = new int[] { 3, 0, 2, 1 }; private static void CompressAlphaBlock(BinaryWriter dest, Pixel[] block, int quality) { int num2; int num = num2 = block[0].a; for (int i = 1; i < 0x10; i++) { num = Math.Min(num, block[i].a); num2 = Math.Max(num2, block[i].a); } dest.Write((byte) num2); dest.Write((byte) num); int num4 = num2 - num; int num5 = (num * 7) - (num4 >> 1); int num6 = num4 * 4; int num7 = num4 * 2; int num8 = 0; int num9 = 0; for (int j = 0; j < 0x10; j++) { int num11 = (block[j].a * 7) - num5; int num13 = (num6 - num11) >> 0x1f; int num12 = num13 & 4; num11 -= num6 & num13; num13 = (num7 - num11) >> 0x1f; num12 += num13 & 2; num11 -= num7 & num13; num13 = (num4 - num11) >> 0x1f; num12 += num13 & 1; num12 = -num12 & 7; num12 ^= (2 > num12) ? 1 : 0; num9 |= num12 << num8; num8 += 3; if (num8 >= 8) { dest.Write((byte) num9); num9 = num9 >> 8; num8 -= 8; } } } private static void CompressColorBlock(BinaryWriter dest, Pixel[] block, int quality, Pixel[] tmppixels16, Pixel[] tmppixels4) { uint num2; ushort num4; ushort num5; uint num6; Pixel[] pixelArray = tmppixels16; Pixel[] color = tmppixels4; uint num = num2 = block[0].v; for (int i = 1; i < 0x10; i++) { num = Math.Min(num, block[i].v); num2 = Math.Max(num2, block[i].v); } if (num != num2) { if (quality > 0) { DitherBlock(pixelArray, block); } OptimizeColorsBlock((quality > 0) ? pixelArray : block, out num5, out num4); if (num5 != num4) { EvalColors(color, num5, num4); num6 = MatchColorsBlock(block, color, quality != 0); } else { num6 = 0; } if (RefineBlock((quality > 0) ? pixelArray : block, ref num5, ref num4, num6)) { if (num5 != num4) { EvalColors(color, num5, num4); num6 = MatchColorsBlock(block, color, quality != 0); } else { num6 = 0; } } } else { int r = block[0].r; int g = block[0].g; int b = block[0].b; num6 = 0xaaaaaaaa; num5 = (ushort) (((OMatch5[r, 0] << 11) | (OMatch6[g, 0] << 5)) | OMatch5[b, 0]); num4 = (ushort) (((OMatch5[r, 1] << 11) | (OMatch6[g, 1] << 5)) | OMatch5[b, 1]); } if (num5 < num4) { num5 = (ushort) (num5 ^ num4); num4 = (ushort) (num4 ^ num5); num5 = (ushort) (num5 ^ num4); num6 ^= 0x55555555; } dest.Write(num5); dest.Write(num4); dest.Write(num6); } public static Image Decode(byte[] data, out string type) { type = null; if (data == null) { return null; } MemoryStream input = new MemoryStream(data); BinaryReader reader = new BinaryReader(input); if (Encoding.ASCII.GetString(reader.ReadBytes(4)) != "DDS ") { return null; } if (reader.ReadInt32() != 0x7c) { return null; } input.Position += 4L; int height = reader.ReadInt32(); int width = reader.ReadInt32(); input.Position += 8L; int mipmaps = reader.ReadInt32(); input.Position += 0x2cL; if (reader.ReadInt32() != 0x20) { return null; } if ((reader.ReadInt32() & 4) == 0) { return null; } FourCC fourcc = (FourCC) reader.ReadUInt32(); input.Position += 40L; string str = ""; if ((mipmaps == 1) && ((width > 1) || (height > 1))) { str = str + ",nomipgen"; } type = string.Format("DDS:{0}{1}", Encoding.ASCII.GetString(BitConverter.GetBytes((uint) fourcc)), str); return DecodeTextureData(input, fourcc, width, height, mipmaps, 0, false); } private static void DecodeATI1Texture(byte[] pixels, int poffset, int width, int height, byte[] data) { int[] numArray = new int[8]; for (int i = 0; i < height; i += 4) { for (int j = 0; j < width; j += 4) { int startIndex = (((j + 3) >> 2) + (((i + 3) >> 2) * ((width + 3) >> 2))) << 3; ulong num4 = BitConverter.ToUInt64(data, startIndex); numArray[0] = (int) (num4 & ((ulong) 0xffL)); num4 = num4 >> 8; numArray[1] = (int) (num4 & ((ulong) 0xffL)); num4 = num4 >> 8; if (numArray[0] > numArray[1]) { for (int m = 1; m < 7; m++) { numArray[m + 1] = (((7 - m) * numArray[0]) + (m * numArray[1])) / 7; } } else { for (int n = 1; n < 5; n++) { numArray[n + 1] = (((5 - n) * numArray[0]) + (n * numArray[1])) / 5; } numArray[6] = 0; numArray[7] = 0xff; } for (int k = 0; k < 4; k++) { if ((i + k) < height) { int index = (poffset + (j << 2)) + ((height - ((k + i) + 1)) * (width << 2)); int num9 = 0; while (num9 < 4) { if ((j + num9) < width) { byte num11; uint num10 = (uint) numArray[(int) ((IntPtr) (num4 & ((ulong) 7L)))]; num4 = num4 >> 3; pixels[index + 2] = num11 = (byte) num10; pixels[index] = pixels[index + 1] = num11; } num9++; index += 4; } } } } } } private static void DecodeATI2Texture(byte[] pixels, int poffset, int width, int height, byte[] data) { int[] numArray = new int[8]; int[] numArray2 = new int[8]; for (int i = 0; i < height; i += 4) { for (int j = 0; j < width; j += 4) { for (int k = 0; k < 2; k++) { int startIndex = (((j + 3) >> 2) + (((i + 3) >> 2) * ((width + 3) >> 2))) << 4; ulong num5 = BitConverter.ToUInt64(data, startIndex); ulong num6 = BitConverter.ToUInt64(data, startIndex + 8); numArray[0] = (int) (num5 & ((ulong) 0xffL)); num5 = num5 >> 8; numArray[1] = (int) (num5 & ((ulong) 0xffL)); num5 = num5 >> 8; if (numArray[0] > numArray[1]) { for (int n = 1; n < 7; n++) { numArray[n + 1] = (((7 - n) * numArray[0]) + (n * numArray[1])) / 7; } } else { for (int num8 = 1; num8 < 5; num8++) { numArray[num8 + 1] = (((5 - num8) * numArray[0]) + (num8 * numArray[1])) / 5; } numArray[6] = 0; numArray[7] = 0xff; } numArray2[0] = (int) (num6 & ((ulong) 0xffL)); num6 = num6 >> 8; numArray2[1] = (int) (num6 & ((ulong) 0xffL)); num6 = num6 >> 8; if (numArray2[0] > numArray2[1]) { for (int num9 = 1; num9 < 7; num9++) { numArray2[num9 + 1] = (((7 - num9) * numArray2[0]) + (num9 * numArray2[1])) / 7; } } else { for (int num10 = 1; num10 < 5; num10++) { numArray2[num10 + 1] = (((5 - num10) * numArray2[0]) + (num10 * numArray2[1])) / 5; } numArray2[6] = 0; numArray2[7] = 0xff; } for (int m = 0; m < 4; m++) { if ((i + m) < height) { int index = (poffset + (j << 2)) + ((height - ((m + i) + 1)) * (width << 2)); int num13 = 0; while (num13 < 4) { if ((j + num13) < width) { int num14 = numArray[(int) ((IntPtr) (num5 & ((ulong) 7L)))]; num5 = num5 >> 3; int num15 = numArray2[(int) ((IntPtr) (num6 & ((ulong) 7L)))]; num6 = num6 >> 3; double d = Math.Round((double) (Math.Sqrt((double) ((0x4000 - ((num15 - 0x7f) * (num15 - 0x7f))) - ((num14 - 0x7f) * (num14 - 0x7f)))) + 127.0)); if (d > 255.0) { d = 255.0; } else if ((d < 128.0) || double.IsNaN(d)) { d = 128.0; } pixels[index + 2] = (byte) num15; pixels[index + 1] = (byte) num14; pixels[index] = (byte) d; } num13++; index += 4; } } } } } } } private static void DecodeDXT1Texture(byte[] pixels, int poffset, int width, int height, byte[] data) { uint[] numArray = new uint[4]; for (int i = 0; i < height; i += 4) { for (int j = 0; j < width; j += 4) { int startIndex = (((j + 3) >> 2) + (((i + 3) >> 2) * ((width + 3) >> 2))) << 3; ulong num4 = BitConverter.ToUInt64(data, startIndex); uint num5 = (uint) (num4 & ((ulong) 0xffffL)); num4 = num4 >> 0x10; uint num6 = (uint) (num4 & ((ulong) 0xffffL)); num4 = num4 >> 0x10; uint num7 = (uint) ((num5 & 0x1f) << 3); num7 |= num7 >> 5; uint num8 = (uint) (((num5 >> 5) & 0x3f) << 2); num8 |= num8 >> 6; uint num9 = (num5 >> 11) << 3; num9 |= num9 >> 5; uint num10 = (uint) ((num6 & 0x1f) << 3); num10 |= num10 >> 5; uint num11 = (uint) (((num6 >> 5) & 0x3f) << 2); num11 |= num11 >> 6; uint num12 = (num6 >> 11) << 3; num12 |= num12 >> 5; numArray[0] = ((num9 << 0x10) | (num8 << 8)) | num7; numArray[1] = ((num12 << 0x10) | (num11 << 8)) | num10; if (num5 > num6) { numArray[2] = ((uint) (((((2 * num9) + num12) / 3) << 0x10) | ((((2 * num8) + num11) / 3) << 8))) | (((2 * num7) + num10) / 3); numArray[3] = ((uint) ((((num9 + (2 * num12)) / 3) << 0x10) | (((num8 + (2 * num11)) / 3) << 8))) | ((num7 + (2 * num10)) / 3); } else { numArray[2] = ((((num9 + num12) >> 1) << 0x10) | (((num8 + num11) >> 1) << 8)) | ((num7 + num10) >> 1); numArray[3] = 510; } for (int k = 0; k < 4; k++) { int index = (poffset + (j << 2)) + ((height - ((k + i) + 1)) * (width << 2)); int num15 = 0; while (num15 < 4) { if ((j + num15) < width) { BitConverter.GetBytes(numArray[(int) ((IntPtr) (num4 & ((ulong) 3L)))]).CopyTo(pixels, index); } num4 = num4 >> 2; num15++; index += 4; } } } } } private static void DecodeDXT5AlphaBlock(int[] pixels, int poffset, byte[] data, int doffset, int[] alphavals) { ulong num = BitConverter.ToUInt64(data, doffset); alphavals[0] = (int) (num & ((ulong) 0xffL)); num = num >> 8; alphavals[1] = (int) (num & ((ulong) 0xffL)); num = num >> 8; if (alphavals[0] > alphavals[1]) { for (int j = 1; j < 7; j++) { alphavals[j + 1] = (((7 - j) * alphavals[0]) + (j * alphavals[1])) / 7; } } else { for (int k = 1; k < 5; k++) { alphavals[k + 1] = (((5 - k) * alphavals[0]) + (k * alphavals[1])) / 5; } alphavals[6] = 0; alphavals[7] = 0xff; } for (int i = 0; i < 4; i++) { for (int m = 0; m < 4; m++) { pixels[((i * 4) + m) + poffset] = alphavals[(int) ((IntPtr) (num & ((ulong) 7L)))]; num = num >> 3; } } } private static void DecodeDXT5Texture(byte[] pixels, int poffset, int width, int height, byte[] data) { uint[] numArray = new uint[8]; uint[] numArray2 = new uint[4]; for (int i = 0; i < height; i += 4) { for (int j = 0; j < width; j += 4) { int startIndex = (((j + 3) >> 2) + (((i + 3) >> 2) * ((width + 3) >> 2))) << 4; ulong num4 = BitConverter.ToUInt64(data, startIndex); numArray[0] = (uint) (num4 & ((ulong) 0xffL)); num4 = num4 >> 8; numArray[1] = (uint) (num4 & ((ulong) 0xffL)); num4 = num4 >> 8; if (numArray[0] > numArray[1]) { for (int m = 1; m < 7; m++) { numArray[m + 1] = (uint) ((((uint) (((7 - m) * numArray[0]) + (m * numArray[1]))) / 7) << 0x18); } } else { for (int n = 1; n < 5; n++) { numArray[n + 1] = (uint) ((((uint) (((5 - n) * numArray[0]) + (n * numArray[1]))) / 5) << 0x18); } numArray[6] = 0; numArray[7] = 0xff000000; } numArray[0] = numArray[0] << 0x18; numArray[1] = numArray[1] << 0x18; ulong num7 = BitConverter.ToUInt64(data, startIndex + 8); uint num8 = (uint) (num7 & ((ulong) 0xffffL)); num7 = num7 >> 0x10; uint num9 = (uint) (num7 & ((ulong) 0xffffL)); num7 = num7 >> 0x10; uint num10 = (uint) ((num8 & 0x1f) << 3); num10 |= num10 >> 5; uint num11 = (uint) (((num8 >> 5) & 0x3f) << 2); num11 |= num11 >> 6; uint num12 = (num8 >> 11) << 3; num12 |= num12 >> 5; uint num13 = (uint) ((num9 & 0x1f) << 3); num13 |= num13 >> 5; uint num14 = (uint) (((num9 >> 5) & 0x3f) << 2); num14 |= num14 >> 6; uint num15 = (num9 >> 11) << 3; num15 |= num15 >> 5; numArray2[0] = ((num12 << 0x10) | (num11 << 8)) | num10; numArray2[1] = ((num15 << 0x10) | (num14 << 8)) | num13; numArray2[2] = ((uint) (((((2 * num12) + num15) / 3) << 0x10) | ((((2 * num11) + num14) / 3) << 8))) | (((2 * num10) + num13) / 3); numArray2[3] = ((uint) ((((num12 + (2 * num15)) / 3) << 0x10) | (((num11 + (2 * num14)) / 3) << 8))) | ((num10 + (2 * num13)) / 3); for (int k = 0; k < 4; k++) { int index = (poffset + (j << 2)) + ((height - ((k + i) + 1)) * (width << 2)); int num18 = 0; while (num18 < 4) { if ((j + num18) < width) { uint num19 = numArray[(int) ((IntPtr) (num4 & ((ulong) 7L)))] | numArray2[(int) ((IntPtr) (num7 & ((ulong) 3L)))]; BitConverter.GetBytes(num19).CopyTo(pixels, index); } num4 = num4 >> 3; num7 = num7 >> 2; num18++; index += 4; } } } } } private static Image DecodeTextureData(Stream file, FourCC fourcc, int width, int height, int mipmaps, int mipmapno, bool mipmapreversed) { uint num = GetMipMapOffset(fourcc, width, height, mipmaps, mipmapno, mipmapreversed); uint num2 = GetMipMapSize(fourcc, width, height, mipmaps, mipmapno); if ((num2 == 0) || (((num2 + num) + file.Position) > file.Length)) { return null; } width = ((width + (1 << (mipmapno & 0x1f))) - 1) >> mipmapno; height = ((height + (1 << (mipmapno & 0x1f))) - 1) >> mipmapno; file.Seek((long) num, SeekOrigin.Current); byte[] buffer = new byte[num2]; file.Read(buffer, 0, (int) num2); byte[] array = new byte[0x36 + ((width * height) * 4)]; array[0] = 0x42; array[1] = 0x4d; BitConverter.GetBytes(array.Length).CopyTo(array, 2); array[10] = 0x36; array[14] = 40; BitConverter.GetBytes(width).CopyTo(array, 0x12); BitConverter.GetBytes(height).CopyTo(array, 0x16); array[0x1a] = 1; array[0x1c] = 0x20; BitConverter.GetBytes((int) ((width * height) * 4)).CopyTo(array, 0x22); switch (fourcc) { case FourCC.ATI2: DecodeATI2Texture(array, 0x36, width, height, buffer); break; case FourCC.DXT5: DecodeDXT5Texture(array, 0x36, width, height, buffer); break; case FourCC.ATI1: DecodeATI1Texture(array, 0x36, width, height, buffer); break; case FourCC.DXT1: DecodeDXT1Texture(array, 0x36, width, height, buffer); break; } MemoryStream stream = new MemoryStream(array); using (stream) { return new Bitmap(Image.FromStream(stream)); } } private static void DitherBlock(Pixel[] dest, Pixel[] block) { int[] numArray = new int[8]; int index = 0; int num2 = 4; for (int i = 0; i < 3; i++) { int num4 = 0; int num5 = 8; byte[] buffer = (i == 1) ? QuantGTab : QuantRBTab; for (int j = 0; j < numArray.Length; j++) { numArray[j] = 0; } for (int k = 0; k < 4; k++) { dest[num4].components[i] = buffer[(num5 + block[num4].components[i]) + (((3 * numArray[num2 + 1]) + (5 * numArray[num2])) >> 4)]; numArray[index] = block[num4].components[i] - dest[num4].components[i]; dest[num4 + 1].components[i] = buffer[(num5 + block[num4 + 1].components[i]) + (((((7 * numArray[index]) + (3 * numArray[num2 + 2])) + (5 * numArray[num2 + 1])) + numArray[num2]) >> 4)]; numArray[index + 1] = block[num4 + 1].components[i] - dest[num4 + 1].components[i]; dest[num4 + 2].components[i] = buffer[(num5 + block[num4 + 2].components[i]) + (((((7 * numArray[index + 1]) + (3 * numArray[num2 + 3])) + (5 * numArray[num2 + 2])) + numArray[num2 + 1]) >> 4)]; numArray[index + 2] = block[num4 + 2].components[i] - dest[num4 + 2].components[i]; dest[num4 + 3].components[i] = buffer[(num5 + block[num4 + 3].components[i]) + ((((7 * numArray[index + 2]) + (5 * numArray[num2 + 3])) + numArray[num2 + 2]) >> 4)]; numArray[index + 3] = block[num4 + 3].components[i] - dest[num4 + 3].components[i]; index = num2; num2 = 4 - num2; num4 += 4; } } } public static byte[] Encode(Image data, string type) { int quality = 1; FourCC encodertype = FourCC.DXT1; bool flag = true; foreach (string str in type.Substring(4).Split(new char[] { ',' })) { string str2 = str.ToLower(); if (str2 == null) { goto Label_0094; } if (!(str2 == "dxt1")) { if (str2 == "dxt5") { goto Label_0084; } if (str2 == "nomipgen") { goto Label_008C; } if (str2 == "nodither") { goto Label_0090; } goto Label_0094; } encodertype = FourCC.DXT1; goto Label_00A6; Label_0084: encodertype = FourCC.DXT5; goto Label_00A6; Label_008C: flag = false; goto Label_00A6; Label_0090: quality = 0; goto Label_00A6; Label_0094: throw new Exception(string.Format("Bad DDS encoder parameter: {0}", str)); Label_00A6:; } int num2 = 0; int num3 = 0; while ((((int) 1) << num2) < data.Width) { num2++; } while ((((int) 1) << num3) < data.Height) { num3++; } while ((((int) 1) << num2) > 0x400) { num2--; } while ((((int) 1) << num3) > 0x400) { num3--; } int num4 = 1; if (flag) { num4 = Math.Max((int) (num2 + 1), (int) (num3 + 1)); } MemoryStream output = new MemoryStream(); using (output) { BinaryWriter bw = new BinaryWriter(output); bw.Write((uint) 0x20534444); bw.Write((uint) 0x7c); bw.Write((uint) 0x61007); bw.Write((uint) (((uint) 1) << num3)); bw.Write((uint) (((uint) 1) << num2)); bw.Write((uint) (((((((int) 1) << num3) + 3) / 4) * (((((int) 1) << num2) + 3) / 4)) * ((encodertype == FourCC.DXT1) ? 8 : 0x10))); bw.Write((uint) 1); bw.Write(num4); for (int i = 0; i < 11; i++) { bw.Write((uint) 0); } bw.Write((uint) 0x20); bw.Write((uint) 4); bw.Write((uint) encodertype); for (int j = 0; j < 5; j++) { bw.Write((uint) 0); } bw.Write((uint) 0x401000); for (int k = 0; k < 4; k++) { bw.Write((uint) 0); } sInitDXT(); Bitmap image = new Bitmap(((int) 1) << num2, ((int) 1) << num3, PixelFormat.Format32bppArgb); using (image) { Graphics graphics = Graphics.FromImage(image); using (graphics) { graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.SmoothingMode = SmoothingMode.HighQuality; for (int m = 0; m < num4; m++) { int num9; int num10; if (m > num2) { num9 = 1; } else { num9 = ((int) 1) << (num2 - m); } if (m > num3) { num10 = 1; } else { num10 = ((int) 1) << (num3 - m); } graphics.DrawImage(data, 0, 0, num9, num10); EncodeDDS(bw, image, num9, num10, encodertype, quality); } } } return output.GetBuffer(); } } private static void EncodeDDS(BinaryWriter bw, Bitmap bm, int width, int height, FourCC encodertype, int quality) { byte[] buffer; Rectangle rect = new Rectangle(0, 0, width, height); BitmapData bitmapdata = bm.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); try { buffer = new byte[bitmapdata.Stride * bitmapdata.Height]; Marshal.Copy(bitmapdata.Scan0, buffer, 0, buffer.Length); } finally { bm.UnlockBits(bitmapdata); } Pixel[] src = new Pixel[0x10]; Pixel[] pixelArray2 = new Pixel[0x10]; Pixel[] pixelArray3 = new Pixel[4]; for (int i = 0; i < 0x10; i++) { src[i] = new Pixel(); pixelArray2[i] = new Pixel(); if (i < 4) { pixelArray3[i] = new Pixel(); } } for (int j = 0; j < height; j += 4) { for (int k = 0; k < width; k += 4) { for (int m = 0; m < 4; m++) { for (int n = 0; n < 4; n++) { int num6 = (k + n) & (width - 1); int num7 = (j + m) & (height - 1); Array.Copy(buffer, (bitmapdata.Stride * num7) + (4 * num6), src[(m * 4) + n].components, 0, 4); } } sCompressDXTBlock(bw, src, encodertype == FourCC.DXT5, quality, pixelArray2, pixelArray3); } } } private static void EvalColors(Pixel[] color, ushort c0, ushort c1) { color[0].From16Bit(c0); color[1].From16Bit(c1); color[2].LerpRGB(color[0], color[1], 0x55); color[3].LerpRGB(color[0], color[1], 170); } private static uint GetMipMapOffset(FourCC fourcc, int width, int height, int mipmaps, int mipmapno, bool mipmapreversed) { uint num = 0; if (mipmapreversed) { for (int j = mipmaps - 1; j > mipmapno; j--) { num += GetMipMapSize(fourcc, width, height, mipmaps, j); } return num; } for (int i = mipmapno; i > 0; i--) { num += GetMipMapSize(fourcc, width, height, mipmaps, i - 1); } return num; } private static uint GetMipMapSize(FourCC fourcc, int width, int height, int mipmaps, int mipmapno) { width = ((width + (1 << (mipmapno & 0x1f))) - 1) >> mipmapno; height = ((height + (1 << (mipmapno & 0x1f))) - 1) >> mipmapno; switch (fourcc) { case FourCC.ATI1: return (uint) ((((width + 3) / 4) * ((height + 3) / 4)) * 8); case FourCC.DXT1: return (uint) ((((width + 3) / 4) * ((height + 3) / 4)) * 8); case FourCC.ATI2: return (uint) ((((width + 3) / 4) * ((height + 3) / 4)) * 0x10); case FourCC.DXT5: return (uint) ((((width + 3) / 4) * ((height + 3) / 4)) * 0x10); } return 0; } private static uint MatchColorsBlock(Pixel[] block, Pixel[] color, bool dither) { uint num = 0; int num2 = color[0].r - color[1].r; int num3 = color[0].g - color[1].g; int num4 = color[0].b - color[1].b; int[] numArray = new int[0x10]; for (int i = 0; i < 0x10; i++) { numArray[i] = ((block[i].r * num2) + (block[i].g * num3)) + (block[i].b * num4); } int[] numArray2 = new int[4]; for (int j = 0; j < 4; j++) { numArray2[j] = ((color[j].r * num2) + (color[j].g * num3)) + (color[j].b * num4); } int num7 = (numArray2[1] + numArray2[3]) >> 1; int num8 = (numArray2[3] + numArray2[2]) >> 1; int num9 = (numArray2[2] + numArray2[0]) >> 1; if (!dither) { for (int n = 15; n >= 0; n--) { num = num << 2; int num11 = numArray[n]; if (num11 < num8) { num |= (uint)((num11 < num7) ? 1 : 3); } else { num |= (uint)((num11 < num9) ? 2 : 0); } } return num; } int[] numArray3 = new int[8]; int index = 0; int num13 = 4; int num14 = 0; num7 = num7 << 4; num8 = num8 << 4; num9 = num9 << 4; for (int k = 0; k < 8; k++) { numArray3[k] = 0; } for (int m = 0; m < 4; m++) { int num19; int num17 = (numArray[num14] << 4) + ((3 * numArray3[num13 + 1]) + (5 * numArray3[num13])); if (num17 < num8) { num19 = (num17 < num7) ? 1 : 3; } else { num19 = (num17 < num9) ? 2 : 0; } numArray3[index] = numArray[num14] - numArray2[num19]; int num18 = num19; num17 = (numArray[num14 + 1] << 4) + ((((7 * numArray3[index]) + (3 * numArray3[num13 + 2])) + (5 * numArray3[num13 + 1])) + numArray3[num13]); if (num17 < num8) { num19 = (num17 < num7) ? 1 : 3; } else { num19 = (num17 < num9) ? 2 : 0; } numArray3[index + 1] = numArray[num14 + 1] - numArray2[num19]; num18 |= num19 << 2; num17 = (numArray[num14 + 2] << 4) + ((((7 * numArray3[index + 1]) + (3 * numArray3[num13 + 3])) + (5 * numArray3[num13 + 2])) + numArray3[num13 + 1]); if (num17 < num8) { num19 = (num17 < num7) ? 1 : 3; } else { num19 = (num17 < num9) ? 2 : 0; } numArray3[index + 2] = numArray[num14 + 2] - numArray2[num19]; num18 |= num19 << 4; num17 = (numArray[num14 + 3] << 4) + (((7 * numArray3[index + 2]) + (5 * numArray3[num13 + 3])) + numArray3[num13 + 2]); if (num17 < num8) { num19 = (num17 < num7) ? 1 : 3; } else { num19 = (num17 < num9) ? 2 : 0; } numArray3[index + 3] = numArray[num14 + 3] - numArray2[num19]; num18 |= num19 << 6; index = num13; num13 = 4 - num13; num14 += 4; num |= (uint) (num18 << (m * 8)); } return num; } private static int Mul8Bit(int a, int b) { int num = (a * b) + 0x80; return ((num + (num >> 8)) >> 8); } private static void OptimizeColorsBlock(Pixel[] block, out ushort max16, out ushort min16) { int num22; int num23; int num24; int[] numArray = new int[3]; int[] numArray2 = new int[3]; int[] numArray3 = new int[3]; for (int i = 0; i < 3; i++) { int num4; int num5; int index = 0; int num3 = num4 = num5 = block[index].components[i]; for (int num6 = 0; num6 < 0x10; num6++) { int num7 = block[index + num6].components[i]; num3 += num7; num4 = Math.Min(num4, num7); num5 = Math.Max(num5, num7); } numArray[i] = (num3 + 8) >> 4; numArray2[i] = num4; numArray3[i] = num5; } int[] numArray4 = new int[6]; for (int j = 0; j < 6; j++) { numArray4[j] = 0; } for (int k = 0; k < 0x10; k++) { int num10 = block[k].r - numArray[2]; int num11 = block[k].g - numArray[1]; int num12 = block[k].b - numArray[0]; numArray4[0] += num10 * num10; numArray4[1] += num10 * num11; numArray4[2] += num10 * num12; numArray4[3] += num11 * num11; numArray4[4] += num11 * num12; numArray4[5] += num12 * num12; } float[] numArray5 = new float[6]; for (int m = 0; m < 6; m++) { numArray5[m] = ((float) numArray4[m]) / 255f; } float num13 = numArray3[2] - numArray2[2]; float num14 = numArray3[1] - numArray2[1]; float num15 = numArray3[0] - numArray2[0]; for (int n = 0; n < nIterPower; n++) { float num18 = ((num13 * numArray5[0]) + (num14 * numArray5[1])) + (num15 * numArray5[2]); float num19 = ((num13 * numArray5[1]) + (num14 * numArray5[3])) + (num15 * numArray5[4]); float num20 = ((num13 * numArray5[2]) + (num14 * numArray5[4])) + (num15 * numArray5[5]); num13 = num18; num14 = num19; num15 = num20; } float num21 = Math.Max(Math.Max(Math.Abs(num13), Math.Abs(num14)), Math.Abs(num15)); if (num21 < 4f) { num22 = 0x94; num23 = 300; num24 = 0x3a; } else { num21 = 512f / num21; num22 = (int) (num13 * num21); num23 = (int) (num14 * num21); num24 = (int) (num15 * num21); } int num25 = 0x7fffffff; int num26 = -2147483647; Pixel pixel = new Pixel(); Pixel pixel2 = new Pixel(); for (int num27 = 0; num27 < 0x10; num27++) { int num28 = ((block[num27].r * num22) + (block[num27].g * num23)) + (block[num27].b * num24); if (num28 < num25) { num25 = num28; pixel = block[num27]; } if (num28 > num26) { num26 = num28; pixel2 = block[num27]; } } max16 = pixel2.As16Bit(); min16 = pixel.As16Bit(); } private static void PrepareOptTable(byte[,] Table, byte[] expand, int size) { for (int i = 0; i < 0x100; i++) { int num2 = 0x100; for (int j = 0; j < size; j++) { for (int k = 0; k < size; k++) { int num5 = expand[j]; int num6 = expand[k]; int num7 = (num6 + Mul8Bit(num5 - num6, 0x55)) - i; if (num7 < 0) { num7 = -num7; } if (num7 < num2) { Table[i, 0] = (byte) k; Table[i, 1] = (byte) j; num2 = num7; } } } } } private static bool RefineBlock(Pixel[] block, ref ushort max16, ref ushort min16, uint mask) { int num3; int num4; int num6; int num7; int num = 0; uint num8 = mask; int num2 = num3 = num4 = 0; int num5 = num6 = num7 = 0; int index = 0; while (index < 0x10) { int num10 = ((int) num8) & 3; int num11 = w1Tab[num10]; int r = block[index].r; int g = block[index].g; int b = block[index].b; num += prods[num10]; num2 += num11 * r; num3 += num11 * g; num4 += num11 * b; num5 += r; num6 += g; num7 += b; index++; num8 = num8 >> 2; } num5 = (3 * num5) - num2; num6 = (3 * num6) - num3; num7 = (3 * num7) - num4; int num15 = num >> 0x10; int num16 = (num >> 8) & 0xff; int num17 = num & 0xff; if (((num16 == 0) || (num15 == 0)) || ((num15 * num16) == (num17 * num17))) { return false; } float num18 = 0.3647059f / ((float) ((num15 * num16) - (num17 * num17))); float num19 = (num18 * 63f) / 31f; ushort num20 = min16; ushort num21 = max16; max16 = (ushort) (((uint) Math.Min(Math.Max((float) ((((num2 * num16) - (num5 * num17)) * num18) + 0.5f), (float) 0f), 31f)) << 11); max16 = (ushort) (max16 | ((ushort) (((uint) Math.Min(Math.Max((float) ((((num3 * num16) - (num6 * num17)) * num19) + 0.5f), (float) 0f), 63f)) << 5))); max16 = (ushort) (max16 | ((ushort) ((uint) Math.Min(Math.Max((float) ((((num4 * num16) - (num7 * num17)) * num18) + 0.5f), (float) 0f), 31f)))); min16 = (ushort) (((uint) Math.Min(Math.Max((float) ((((num5 * num15) - (num2 * num17)) * num18) + 0.5f), (float) 0f), 31f)) << 11); min16 = (ushort) (min16 | ((ushort) (((uint) Math.Min(Math.Max((float) ((((num6 * num15) - (num3 * num17)) * num19) + 0.5f), (float) 0f), 63f)) << 5))); min16 = (ushort) (min16 | ((ushort) ((uint) Math.Min(Math.Max((float) ((((num7 * num15) - (num4 * num17)) * num18) + 0.5f), (float) 0f), 31f)))); if (num20 == min16) { return (num21 != max16); } return true; } private static void sCompressDXTBlock(BinaryWriter dest, Pixel[] src, bool alpha, int quality, Pixel[] tmppixels16, Pixel[] tmppixels4) { if (alpha) { CompressAlphaBlock(dest, src, quality); } CompressColorBlock(dest, src, quality, tmppixels16, tmppixels4); } private static void sInitDXT() { if (!sInitted) { sInitted = true; for (int i = 0; i < 0x20; i++) { Expand5[i] = (byte) ((i << 3) | (i >> 2)); } for (int j = 0; j < 0x40; j++) { Expand6[j] = (byte) ((j << 2) | (j >> 4)); } for (int k = 0; k < 0x110; k++) { int a = Math.Min(Math.Max(k - 8, 0), 0xff); QuantRBTab[k] = Expand5[Mul8Bit(a, 0x1f)]; QuantGTab[k] = Expand6[Mul8Bit(a, 0x3f)]; } PrepareOptTable(OMatch5, Expand5, 0x20); PrepareOptTable(OMatch6, Expand6, 0x40); } } public enum FourCC { ATI1 = 0x31495441, ATI2 = 0x32495441, DDS = 0x20534444, DXT1 = 0x31545844, DXT2 = 0x32545844, DXT3 = 0x33545844, DXT4 = 0x34545844, DXT5 = 0x35545844 } private class Pixel { public byte[] components = new byte[4]; public ushort As16Bit() { return (ushort) (((DDS.Mul8Bit(this.r, 0x1f) << 11) + (DDS.Mul8Bit(this.g, 0x3f) << 5)) + DDS.Mul8Bit(this.b, 0x1f)); } public void From16Bit(ushort v) { int index = (v & 0xf800) >> 11; int num2 = (v & 0x7e0) >> 5; int num3 = v & 0x1f; this.a = 0; this.r = DDS.Expand5[index]; this.g = DDS.Expand6[num2]; this.b = DDS.Expand5[num3]; } public void LerpRGB(DDS.Pixel p1, DDS.Pixel p2, int f) { this.r = (byte) (p1.r + DDS.Mul8Bit(p2.r - p1.r, f)); this.g = (byte) (p1.g + DDS.Mul8Bit(p2.g - p1.g, f)); this.b = (byte) (p1.b + DDS.Mul8Bit(p2.b - p1.b, f)); } public byte a { get { return this.components[3]; } set { this.components[3] = value; } } public byte b { get { return this.components[0]; } set { this.components[0] = value; } } public byte g { get { return this.components[1]; } set { this.components[1] = value; } } public byte r { get { return this.components[2]; } set { this.components[2] = value; } } public uint v { get { return BitConverter.ToUInt32(this.components, 0); } set { this.components = BitConverter.GetBytes(value); } } } } }