Guest User

Untitled

a guest
Jun 9th, 2013
399
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 18.31 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Runtime.InteropServices;
  7. using System.IO;
  8. using System.Drawing;
  9.  
  10. namespace Tex2Png
  11. {
  12.     /// <summary>
  13.     /// Loads a wildstar .tex file and provides the possibility
  14.     /// to save it as a png to a file.
  15.     /// </summary>
  16.     internal class TexFile
  17.     {
  18.         private List<uint[]> mLayerData = new List<uint[]>();
  19.         TexHeader mHeader;
  20.  
  21.         /// <summary>
  22.         /// Constructs and loads the tex file from a file on the
  23.         /// hard disc
  24.         /// </summary>
  25.         /// <param name="fileName">Path to the file on the harddisc</param>
  26.         public TexFile(string fileName)
  27.         {
  28.             LoadData(fileName);
  29.         }
  30.  
  31.         /// <summary>
  32.         /// Saves the image to the harddisc using the path specified
  33.         /// in the fileName parameter with its extension replaced with
  34.         /// PNG. Thus the image is stored as a png image.
  35.         /// </summary>
  36.         /// <param name="fileName">Name of the destination file</param>
  37.         public unsafe void Save(string fileName)
  38.         {
  39.             var layer = mLayerData.Last();
  40.  
  41.             Bitmap bmp = new Bitmap(mHeader.width, mHeader.height);
  42.             var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly,
  43.                 System.Drawing.Imaging.PixelFormat.Format32bppArgb);
  44.  
  45.             fixed (uint* ptr = layer)
  46.             {
  47.                 CopyMemory(data.Scan0, (IntPtr)ptr, (uint)(layer.Length * 4));
  48.             }
  49.  
  50.             bmp.UnlockBits(data);
  51.             bmp.Save(Path.GetDirectoryName(fileName) + "\\" + Path.GetFileNameWithoutExtension(fileName) + ".png",
  52.                 System.Drawing.Imaging.ImageFormat.Png);
  53.  
  54.         }
  55.  
  56.         private unsafe void LoadData(string file)
  57.         {
  58.             var strm = File.OpenRead(file);
  59.             using (BinaryReader reader = new BinaryReader(strm))
  60.             {
  61.                 TexHeader header = Read<TexHeader>(reader);
  62.                 mHeader = header;
  63.                 if (header.sides != 1 || header.depth != 1)
  64.                 {
  65.                     throw new InvalidOperationException("3D-Texture are not supported for conversion.");
  66.                 }
  67.  
  68.                 var fmt = FormatEntries[header.textureFormatIndex];
  69.                 if (fmt.format == -1)
  70.                     throw new InvalidOperationException("Textureformat " + header.textureFormatIndex + " is not yet fully reversed, cannot convert.");
  71.  
  72.                 // mip maps are stored from smallest to largest
  73.                 for (int i = header.mipCount - 1; i >= 0; --i)
  74.                 {
  75.                     int curw = header.width >> i;
  76.                     int curh = header.height >> i;
  77.  
  78.                     if (curw < 1) curw = 1;
  79.                     if (curh < 1) curh = 1;
  80.  
  81.                     if (fmt.format == 1)
  82.                     {
  83.                         mLayerData.Add(LoadLayerDXT1(reader, curw, curh));
  84.                     }
  85.                     else if (fmt.format == 2)
  86.                     {
  87.                         mLayerData.Add(LoadLayerDXT3(reader, curw, curh));
  88.                     }
  89.                     else if (fmt.format == 3)
  90.                     {
  91.                         mLayerData.Add(LoadLayerDXT5(reader, curw, curh));
  92.                     }
  93.                     else if (fmt.format == 0)
  94.                     {
  95.                         mLayerData.Add(Read(new uint[curw * curh], reader));
  96.                     }
  97.                 }
  98.             }
  99.         }
  100.  
  101.         private uint[] LoadLayerDXT5(BinaryReader reader, int width, int height)
  102.         {
  103.             List<uint> ret = new List<uint>();
  104.             int numBlocksFull = (width * height) / 16;
  105.             bool partialBlock = ((width * height) % 16) != 0;
  106.  
  107.             List<uint[]> blocks = new List<uint[]>();
  108.  
  109.             for (int i = 0; i < numBlocksFull; ++i)
  110.             {
  111.                 blocks.Add(DXT5GetBlock(reader, 4, 4));
  112.             }
  113.  
  114.             if (partialBlock != false)
  115.                 blocks.Add(DXT5GetBlock(reader, 4, 4));
  116.  
  117.             for (int y = 0; y < height; ++y)
  118.             {
  119.                 for (int x = 0; x < width; ++x)
  120.                 {
  121.                     int bx = x / 4;
  122.                     int by = y / 4;
  123.  
  124.                     int ibx = x % 4;
  125.                     int iby = y % 4;
  126.  
  127.                     int blockIndex = by * (width / 4) + bx;
  128.                     int innerIndex = iby * 4 + ibx;
  129.  
  130.                     ret.Add(blocks[blockIndex][innerIndex]);
  131.                 }
  132.             }
  133.  
  134.             return ret.ToArray();
  135.         }
  136.  
  137.         private uint[] LoadLayerDXT3(BinaryReader reader, int width, int height)
  138.         {
  139.             List<uint> ret = new List<uint>();
  140.             int numBlocksFull = (width * height) / 16;
  141.             bool partialBlock = ((width * height) % 16) != 0;
  142.  
  143.             List<uint[]> blocks = new List<uint[]>();
  144.  
  145.             for (int i = 0; i < numBlocksFull; ++i)
  146.             {
  147.                 blocks.Add(DXT3GetBlock(reader, 4, 4));
  148.             }
  149.  
  150.             if (partialBlock != false)
  151.                 blocks.Add(DXT3GetBlock(reader, 4, 4));
  152.  
  153.             for (int y = 0; y < height; ++y)
  154.             {
  155.                 for (int x = 0; x < width; ++x)
  156.                 {
  157.                     int bx = x / 4;
  158.                     int by = y / 4;
  159.  
  160.                     int ibx = x % 4;
  161.                     int iby = y % 4;
  162.  
  163.                     int blockIndex = by * (width / 4) + bx;
  164.                     int innerIndex = iby * 4 + ibx;
  165.  
  166.                     ret.Add(blocks[blockIndex][innerIndex]);
  167.                 }
  168.             }
  169.  
  170.             return ret.ToArray();
  171.         }
  172.  
  173.         private uint[] LoadLayerDXT1(BinaryReader reader, int width, int height)
  174.         {
  175.             List<uint> ret = new List<uint>();
  176.             int numBlocksFull = (width * height) / 16;
  177.             bool partialBlock = ((width * height) % 16) != 0;
  178.            
  179.             List<uint[]> blocks = new List<uint[]>();
  180.  
  181.             for (int i = 0; i < numBlocksFull; ++i)
  182.             {
  183.                 blocks.Add(DXT1GetBlock(reader, 4, 4));
  184.             }
  185.  
  186.             if (partialBlock != false)
  187.                 blocks.Add(DXT1GetBlock(reader, 4, 4));
  188.  
  189.             for (int y = 0; y < height; ++y)
  190.             {
  191.                 for (int x = 0; x < width; ++x)
  192.                 {
  193.                     int bx = x / 4;
  194.                     int by = y / 4;
  195.  
  196.                     int ibx = x % 4;
  197.                     int iby = y % 4;
  198.  
  199.                     int blockIndex = by * (width / 4) + bx;
  200.                     int innerIndex = iby * 4 + ibx;
  201.  
  202.                     ret.Add(blocks[blockIndex][innerIndex]);
  203.                 }
  204.             }
  205.  
  206.             return ret.ToArray();
  207.         }
  208.  
  209.         private uint[] DXT5GetBlock(BinaryReader reader, int w, int h)
  210.         {
  211.             byte alpha1 = reader.ReadByte();
  212.             byte alpha2 = reader.ReadByte();
  213.  
  214.             uint[] alphaValues = new uint[8]
  215.             {
  216.                 alpha1,
  217.                 alpha2,
  218.                 0, 0, 0, 0, 0, 0
  219.             };
  220.  
  221.             if (alpha1 > alpha2)
  222.             {
  223.                 for (int i = 0; i < 6; ++i)
  224.                 {
  225.                     byte value = (byte)(((6.0f - i) * alpha1 + (1.0f + i) * alpha2) / 7.0f);
  226.                     alphaValues[i + 2] = value;
  227.                 }
  228.             }
  229.             else
  230.             {
  231.                 for (int i = 0; i < 4; ++i)
  232.                 {
  233.                     byte value = (byte)(((4.0f - i) * alpha1 + (1.0f + i) * alpha2) / 5.0f);
  234.                     alphaValues[i + 2] = value;
  235.                 }
  236.  
  237.                 alphaValues[6] = 0;
  238.                 alphaValues[7] = 255;
  239.             }
  240.  
  241.             int[] alphaLookup = new int[16];
  242.             ulong lookupValue = reader.ReadUInt32();
  243.             lookupValue |= (ulong)((uint)(reader.ReadUInt16()) << 32);
  244.  
  245.             for (int i = 0; i < 16; ++i)
  246.             {
  247.                 alphaLookup[i] = (int)((lookupValue >> (i * 3)) & 7);
  248.             }
  249.  
  250.             var color1 = reader.ReadUInt16();
  251.             var color2 = reader.ReadUInt16();
  252.  
  253.             byte[] clr1 = RGB565ToRGB8Array(color1);
  254.             byte[] clr2 = RGB565ToRGB8Array(color2);
  255.             byte[] clr3 = new byte[3];
  256.             byte[] clr4 = new byte[3];
  257.  
  258.             if (color1 > color2)
  259.             {
  260.                 for (int i = 0; i < 3; ++i)
  261.                 {
  262.                     clr4[i] = (byte)((clr1[i] + 2 * clr2[i]) / 3);
  263.                     clr3[i] = (byte)((2 * clr1[i] + clr2[i]) / 3);
  264.                 }
  265.             }
  266.             else
  267.             {
  268.                 for (int i = 0; i < 3; ++i)
  269.                 {
  270.                     clr3[i] = (byte)((clr1[i] + clr2[i]) / 2);
  271.                     clr4[i] = 0;
  272.                 }
  273.             }
  274.  
  275.             uint[] colors = new uint[]
  276.             {
  277.                 ToOpaqueColor(clr1),
  278.                 ToOpaqueColor(clr2),
  279.                 ToOpaqueColor(clr3),
  280.                 ToOpaqueColor(clr4)
  281.             };
  282.  
  283.             uint indices = reader.ReadUInt32();
  284.             int[] tableIndices = new int[16];
  285.             for (int i = 0; i < 16; ++i)
  286.             {
  287.                 tableIndices[i] = (int)((indices >> (2 * i)) & 3);
  288.             }
  289.  
  290.             uint[] colorRet = new uint[w * h];
  291.             for (int y = 0; y < h; ++y)
  292.             {
  293.                 for (int x = 0; x < w; ++x)
  294.                 {
  295.                     int index = y * 4 + x;
  296.                     var clrTmp = colors[tableIndices[index]];
  297.                     colorRet[y * w + x] = clrTmp;
  298.                 }
  299.             }
  300.  
  301.             return colorRet;
  302.         }
  303.  
  304.         private uint[] DXT3GetBlock(BinaryReader reader, int w, int h)
  305.         {
  306.             ulong alpha = reader.ReadUInt64();
  307.             uint[] alphaValues = new uint[16];
  308.             for (int i = 0; i < 16; ++i)
  309.                 alphaValues[i] = (byte)((alpha >> (4 * i)) & 0xF);
  310.  
  311.             var color1 = reader.ReadUInt16();
  312.             var color2 = reader.ReadUInt16();
  313.  
  314.             byte[] clr1 = RGB565ToRGB8Array(color1);
  315.             byte[] clr2 = RGB565ToRGB8Array(color2);
  316.             byte[] clr3 = new byte[3];
  317.             byte[] clr4 = new byte[3];
  318.  
  319.             if (color1 > color2)
  320.             {
  321.                 for (int i = 0; i < 3; ++i)
  322.                 {
  323.                     clr4[i] = (byte)((clr1[i] + 2 * clr2[i]) / 3);
  324.                     clr3[i] = (byte)((2 * clr1[i] + clr2[i]) / 3);
  325.                 }
  326.             }
  327.             else
  328.             {
  329.                 for (int i = 0; i < 3; ++i)
  330.                 {
  331.                     clr3[i] = (byte)((clr1[i] + clr2[i]) / 2);
  332.                     clr4[i] = 0;
  333.                 }
  334.             }
  335.  
  336.             uint[] colors = new uint[]
  337.             {
  338.                 ToOpaqueColor(clr1),
  339.                 ToOpaqueColor(clr2),
  340.                 ToOpaqueColor(clr3),
  341.                 ToOpaqueColor(clr4)
  342.             };
  343.  
  344.             uint indices = reader.ReadUInt32();
  345.             int[] tableIndices = new int[16];
  346.             for (int i = 0; i < 16; ++i)
  347.             {
  348.                 tableIndices[i] = (int)((indices >> (2 * i)) & 3);
  349.             }
  350.  
  351.             uint[] colorRet = new uint[w * h];
  352.             for (int y = 0; y < h; ++y)
  353.             {
  354.                 for (int x = 0; x < w; ++x)
  355.                 {
  356.                     int index = y * 4 + x;
  357.                     var clrTmp = colors[tableIndices[index]];
  358.                     clrTmp &= 0x00FFFFFFFF;
  359.                     clrTmp |= ((alphaValues[y * 4 + x] << 24));
  360.                     colorRet[y * w + x] = clrTmp;
  361.                 }
  362.             }
  363.  
  364.             return colorRet;
  365.         }
  366.  
  367.         private uint[] DXT1GetBlock(BinaryReader reader, int w, int h)
  368.         {
  369.             var color1 = reader.ReadUInt16();
  370.             var color2 = reader.ReadUInt16();
  371.  
  372.             byte[] clr1 = RGB565ToRGB8Array(color1);
  373.             byte[] clr2 = RGB565ToRGB8Array(color2);
  374.             byte[] clr3 = new byte[3];
  375.             byte[] clr4 = new byte[3];
  376.  
  377.             if (color1 > color2)
  378.             {
  379.                 for (int i = 0; i < 3; ++i)
  380.                 {
  381.                     clr4[i] = (byte)((clr1[i] + 2 * clr2[i]) / 3);
  382.                     clr3[i] = (byte)((2 * clr1[i] + clr2[i]) / 3);
  383.                 }
  384.             }
  385.             else
  386.             {
  387.                 for (int i = 0; i < 3; ++i)
  388.                 {
  389.                     clr3[i] = (byte)((clr1[i] + clr2[i]) / 2);
  390.                     clr4[i] = 0;
  391.                 }
  392.             }
  393.  
  394.             uint[] colors = new uint[]
  395.             {
  396.                 ToOpaqueColor(clr1),
  397.                 ToOpaqueColor(clr2),
  398.                 ToOpaqueColor(clr3),
  399.                 ToOpaqueColor(clr4)
  400.             };
  401.  
  402.             uint indices = reader.ReadUInt32();
  403.             int[] tableIndices = new int[16];
  404.             for(int i = 0; i < 16; ++i)
  405.             {
  406.                 tableIndices[i] = (int)((indices >> (2 * i)) & 3);
  407.             }
  408.  
  409.             uint[] colorRet = new uint[w * h];
  410.             for (int y = 0; y < h; ++y)
  411.             {
  412.                 for (int x = 0; x < w; ++x)
  413.                 {
  414.                     int index = y * 4 + x;
  415.                     colorRet[y * w + x] = colors[tableIndices[index]];
  416.                 }
  417.             }
  418.  
  419.             return colorRet;
  420.         }
  421.  
  422.         private byte[] RGB565ToRGB8Array(ushort input)
  423.         {
  424.             uint r = (uint)(input & 0x1F);
  425.             uint g = (uint)((input >> 5) & 0x3F);
  426.             uint b = (uint)((input >> 11) & 0x1F);
  427.  
  428.             r = (r << 3) | (r >> 2);
  429.             g = (g << 2) | (g >> 4);
  430.             b = (b << 3) | (b >> 2);
  431.  
  432.             return new byte[] { (byte)r, (byte)g, (byte)b };
  433.         }
  434.  
  435.         private uint ToOpaqueColor(byte[] clr)
  436.         {
  437.             return (uint)clr[2] | ((uint)clr[1] << 8) | ((uint)clr[0] << 16) | 0xFF000000;
  438.         }
  439.  
  440.         private unsafe T Read<T>(BinaryReader reader) where T : struct
  441.         {
  442.             int size = Marshal.SizeOf(typeof(T));
  443.             byte[] buffer = new byte[size];
  444.             reader.Read(buffer, 0, size);
  445.  
  446.             fixed (byte* ptr = buffer)
  447.             {
  448.                 return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T));
  449.             }
  450.         }
  451.  
  452.         private unsafe T[] Read<T>(T[] values, BinaryReader reader) where T : struct
  453.         {
  454.             int size = Marshal.SizeOf(typeof(T)) * values.Length;
  455.             byte[] buffer = new byte[size];
  456.             reader.Read(buffer, 0, size);
  457.  
  458.             GCHandle handle = GCHandle.Alloc(values, GCHandleType.Pinned);
  459.             Marshal.Copy(buffer, 0, handle.AddrOfPinnedObject(), size);
  460.             return values;
  461.         }
  462.  
  463.         [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
  464.         static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length);
  465.  
  466.         [StructLayout(LayoutKind.Sequential)]
  467.         private struct TexHeader
  468.         {
  469.             public int signature;
  470.             public int alwaysZero;
  471.             public int width;
  472.             public int height;
  473.             public int depth;
  474.             public int sides;
  475.             public int mipCount;
  476.             public int textureFormatIndex;
  477.         }
  478.  
  479.         struct TextureFormatEntry
  480.         {
  481.             public int v1, v2, v3, v4, v5, v6, v7, v8, v9, blockSize, v11, format;
  482.             public bool compressed;
  483.  
  484.             public TextureFormatEntry(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int v9,
  485.                 int blockSize, int v11, int format, bool compressed)
  486.             {
  487.                 this.v1 = v1;
  488.                 this.v2 = v2;
  489.                 this.v3 = v3;
  490.                 this.v4 = v4;
  491.                 this.v5 = v5;
  492.                 this.v6 = v6;
  493.                 this.v7 = v7;
  494.                 this.v8 = v8;
  495.                 this.v9 = v9;
  496.                 this.blockSize = blockSize;
  497.                 this.v11 = v11;
  498.                 this.format = format;
  499.                 this.compressed = compressed;
  500.             }
  501.         };
  502.  
  503.         TextureFormatEntry[] FormatEntries =
  504.         {
  505.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, 0, false),
  506.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, 0, false),
  507.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
  508.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
  509.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
  510.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
  511.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, -1, false),
  512.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
  513.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
  514.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 8, 0, -1, false),
  515.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
  516.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
  517.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
  518.             new TextureFormatEntry(4, 3, 2, 4, 3, 2, 1, 0, 0, 8, 0, 1, true),
  519.             new TextureFormatEntry(4, 3, 2, 4, 3, 2, 1, 0, 0, 16, 0, 2, true ),
  520.             new TextureFormatEntry(4, 3, 2, 4, 3, 2, 1, 0, 0, 16, 0, 3, true ),
  521.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
  522.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
  523.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 8, 0, -1, false),
  524.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
  525.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 16, 0, -1, false),
  526.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 931135488, -1, false),
  527.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 864026624, -1, false),
  528.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 864026624, -1, false),
  529.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, -1, false),
  530.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
  531.             new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
  532.         };
  533.     }
  534. }
Advertisement
Add Comment
Please, Sign In to add comment