Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Runtime.InteropServices;
- using System.IO;
- using System.Drawing;
- namespace Tex2Png
- {
- /// <summary>
- /// Loads a wildstar .tex file and provides the possibility
- /// to save it as a png to a file.
- /// </summary>
- internal class TexFile
- {
- private List<uint[]> mLayerData = new List<uint[]>();
- TexHeader mHeader;
- /// <summary>
- /// Constructs and loads the tex file from a file on the
- /// hard disc
- /// </summary>
- /// <param name="fileName">Path to the file on the harddisc</param>
- public TexFile(string fileName)
- {
- LoadData(fileName);
- }
- /// <summary>
- /// Saves the image to the harddisc using the path specified
- /// in the fileName parameter with its extension replaced with
- /// PNG. Thus the image is stored as a png image.
- /// </summary>
- /// <param name="fileName">Name of the destination file</param>
- public unsafe void Save(string fileName)
- {
- var layer = mLayerData.Last();
- Bitmap bmp = new Bitmap(mHeader.width, mHeader.height);
- var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly,
- System.Drawing.Imaging.PixelFormat.Format32bppArgb);
- fixed (uint* ptr = layer)
- {
- CopyMemory(data.Scan0, (IntPtr)ptr, (uint)(layer.Length * 4));
- }
- bmp.UnlockBits(data);
- bmp.Save(Path.GetDirectoryName(fileName) + "\\" + Path.GetFileNameWithoutExtension(fileName) + ".png",
- System.Drawing.Imaging.ImageFormat.Png);
- }
- private unsafe void LoadData(string file)
- {
- var strm = File.OpenRead(file);
- using (BinaryReader reader = new BinaryReader(strm))
- {
- TexHeader header = Read<TexHeader>(reader);
- mHeader = header;
- if (header.sides != 1 || header.depth != 1)
- {
- throw new InvalidOperationException("3D-Texture are not supported for conversion.");
- }
- var fmt = FormatEntries[header.textureFormatIndex];
- if (fmt.format == -1)
- throw new InvalidOperationException("Textureformat " + header.textureFormatIndex + " is not yet fully reversed, cannot convert.");
- // mip maps are stored from smallest to largest
- for (int i = header.mipCount - 1; i >= 0; --i)
- {
- int curw = header.width >> i;
- int curh = header.height >> i;
- if (curw < 1) curw = 1;
- if (curh < 1) curh = 1;
- if (fmt.format == 1)
- {
- mLayerData.Add(LoadLayerDXT1(reader, curw, curh));
- }
- else if (fmt.format == 2)
- {
- mLayerData.Add(LoadLayerDXT3(reader, curw, curh));
- }
- else if (fmt.format == 3)
- {
- mLayerData.Add(LoadLayerDXT5(reader, curw, curh));
- }
- else if (fmt.format == 0)
- {
- mLayerData.Add(Read(new uint[curw * curh], reader));
- }
- }
- }
- }
- private uint[] LoadLayerDXT5(BinaryReader reader, int width, int height)
- {
- List<uint> ret = new List<uint>();
- int numBlocksFull = (width * height) / 16;
- bool partialBlock = ((width * height) % 16) != 0;
- List<uint[]> blocks = new List<uint[]>();
- for (int i = 0; i < numBlocksFull; ++i)
- {
- blocks.Add(DXT5GetBlock(reader, 4, 4));
- }
- if (partialBlock != false)
- blocks.Add(DXT5GetBlock(reader, 4, 4));
- for (int y = 0; y < height; ++y)
- {
- for (int x = 0; x < width; ++x)
- {
- int bx = x / 4;
- int by = y / 4;
- int ibx = x % 4;
- int iby = y % 4;
- int blockIndex = by * (width / 4) + bx;
- int innerIndex = iby * 4 + ibx;
- ret.Add(blocks[blockIndex][innerIndex]);
- }
- }
- return ret.ToArray();
- }
- private uint[] LoadLayerDXT3(BinaryReader reader, int width, int height)
- {
- List<uint> ret = new List<uint>();
- int numBlocksFull = (width * height) / 16;
- bool partialBlock = ((width * height) % 16) != 0;
- List<uint[]> blocks = new List<uint[]>();
- for (int i = 0; i < numBlocksFull; ++i)
- {
- blocks.Add(DXT3GetBlock(reader, 4, 4));
- }
- if (partialBlock != false)
- blocks.Add(DXT3GetBlock(reader, 4, 4));
- for (int y = 0; y < height; ++y)
- {
- for (int x = 0; x < width; ++x)
- {
- int bx = x / 4;
- int by = y / 4;
- int ibx = x % 4;
- int iby = y % 4;
- int blockIndex = by * (width / 4) + bx;
- int innerIndex = iby * 4 + ibx;
- ret.Add(blocks[blockIndex][innerIndex]);
- }
- }
- return ret.ToArray();
- }
- private uint[] LoadLayerDXT1(BinaryReader reader, int width, int height)
- {
- List<uint> ret = new List<uint>();
- int numBlocksFull = (width * height) / 16;
- bool partialBlock = ((width * height) % 16) != 0;
- List<uint[]> blocks = new List<uint[]>();
- for (int i = 0; i < numBlocksFull; ++i)
- {
- blocks.Add(DXT1GetBlock(reader, 4, 4));
- }
- if (partialBlock != false)
- blocks.Add(DXT1GetBlock(reader, 4, 4));
- for (int y = 0; y < height; ++y)
- {
- for (int x = 0; x < width; ++x)
- {
- int bx = x / 4;
- int by = y / 4;
- int ibx = x % 4;
- int iby = y % 4;
- int blockIndex = by * (width / 4) + bx;
- int innerIndex = iby * 4 + ibx;
- ret.Add(blocks[blockIndex][innerIndex]);
- }
- }
- return ret.ToArray();
- }
- private uint[] DXT5GetBlock(BinaryReader reader, int w, int h)
- {
- byte alpha1 = reader.ReadByte();
- byte alpha2 = reader.ReadByte();
- uint[] alphaValues = new uint[8]
- {
- alpha1,
- alpha2,
- 0, 0, 0, 0, 0, 0
- };
- if (alpha1 > alpha2)
- {
- for (int i = 0; i < 6; ++i)
- {
- byte value = (byte)(((6.0f - i) * alpha1 + (1.0f + i) * alpha2) / 7.0f);
- alphaValues[i + 2] = value;
- }
- }
- else
- {
- for (int i = 0; i < 4; ++i)
- {
- byte value = (byte)(((4.0f - i) * alpha1 + (1.0f + i) * alpha2) / 5.0f);
- alphaValues[i + 2] = value;
- }
- alphaValues[6] = 0;
- alphaValues[7] = 255;
- }
- int[] alphaLookup = new int[16];
- ulong lookupValue = reader.ReadUInt32();
- lookupValue |= (ulong)((uint)(reader.ReadUInt16()) << 32);
- for (int i = 0; i < 16; ++i)
- {
- alphaLookup[i] = (int)((lookupValue >> (i * 3)) & 7);
- }
- var color1 = reader.ReadUInt16();
- var color2 = reader.ReadUInt16();
- byte[] clr1 = RGB565ToRGB8Array(color1);
- byte[] clr2 = RGB565ToRGB8Array(color2);
- byte[] clr3 = new byte[3];
- byte[] clr4 = new byte[3];
- if (color1 > color2)
- {
- for (int i = 0; i < 3; ++i)
- {
- clr4[i] = (byte)((clr1[i] + 2 * clr2[i]) / 3);
- clr3[i] = (byte)((2 * clr1[i] + clr2[i]) / 3);
- }
- }
- else
- {
- for (int i = 0; i < 3; ++i)
- {
- clr3[i] = (byte)((clr1[i] + clr2[i]) / 2);
- clr4[i] = 0;
- }
- }
- uint[] colors = new uint[]
- {
- ToOpaqueColor(clr1),
- ToOpaqueColor(clr2),
- ToOpaqueColor(clr3),
- ToOpaqueColor(clr4)
- };
- uint indices = reader.ReadUInt32();
- int[] tableIndices = new int[16];
- for (int i = 0; i < 16; ++i)
- {
- tableIndices[i] = (int)((indices >> (2 * i)) & 3);
- }
- uint[] colorRet = new uint[w * h];
- for (int y = 0; y < h; ++y)
- {
- for (int x = 0; x < w; ++x)
- {
- int index = y * 4 + x;
- var clrTmp = colors[tableIndices[index]];
- colorRet[y * w + x] = clrTmp;
- }
- }
- return colorRet;
- }
- private uint[] DXT3GetBlock(BinaryReader reader, int w, int h)
- {
- ulong alpha = reader.ReadUInt64();
- uint[] alphaValues = new uint[16];
- for (int i = 0; i < 16; ++i)
- alphaValues[i] = (byte)((alpha >> (4 * i)) & 0xF);
- var color1 = reader.ReadUInt16();
- var color2 = reader.ReadUInt16();
- byte[] clr1 = RGB565ToRGB8Array(color1);
- byte[] clr2 = RGB565ToRGB8Array(color2);
- byte[] clr3 = new byte[3];
- byte[] clr4 = new byte[3];
- if (color1 > color2)
- {
- for (int i = 0; i < 3; ++i)
- {
- clr4[i] = (byte)((clr1[i] + 2 * clr2[i]) / 3);
- clr3[i] = (byte)((2 * clr1[i] + clr2[i]) / 3);
- }
- }
- else
- {
- for (int i = 0; i < 3; ++i)
- {
- clr3[i] = (byte)((clr1[i] + clr2[i]) / 2);
- clr4[i] = 0;
- }
- }
- uint[] colors = new uint[]
- {
- ToOpaqueColor(clr1),
- ToOpaqueColor(clr2),
- ToOpaqueColor(clr3),
- ToOpaqueColor(clr4)
- };
- uint indices = reader.ReadUInt32();
- int[] tableIndices = new int[16];
- for (int i = 0; i < 16; ++i)
- {
- tableIndices[i] = (int)((indices >> (2 * i)) & 3);
- }
- uint[] colorRet = new uint[w * h];
- for (int y = 0; y < h; ++y)
- {
- for (int x = 0; x < w; ++x)
- {
- int index = y * 4 + x;
- var clrTmp = colors[tableIndices[index]];
- clrTmp &= 0x00FFFFFFFF;
- clrTmp |= ((alphaValues[y * 4 + x] << 24));
- colorRet[y * w + x] = clrTmp;
- }
- }
- return colorRet;
- }
- private uint[] DXT1GetBlock(BinaryReader reader, int w, int h)
- {
- var color1 = reader.ReadUInt16();
- var color2 = reader.ReadUInt16();
- byte[] clr1 = RGB565ToRGB8Array(color1);
- byte[] clr2 = RGB565ToRGB8Array(color2);
- byte[] clr3 = new byte[3];
- byte[] clr4 = new byte[3];
- if (color1 > color2)
- {
- for (int i = 0; i < 3; ++i)
- {
- clr4[i] = (byte)((clr1[i] + 2 * clr2[i]) / 3);
- clr3[i] = (byte)((2 * clr1[i] + clr2[i]) / 3);
- }
- }
- else
- {
- for (int i = 0; i < 3; ++i)
- {
- clr3[i] = (byte)((clr1[i] + clr2[i]) / 2);
- clr4[i] = 0;
- }
- }
- uint[] colors = new uint[]
- {
- ToOpaqueColor(clr1),
- ToOpaqueColor(clr2),
- ToOpaqueColor(clr3),
- ToOpaqueColor(clr4)
- };
- uint indices = reader.ReadUInt32();
- int[] tableIndices = new int[16];
- for(int i = 0; i < 16; ++i)
- {
- tableIndices[i] = (int)((indices >> (2 * i)) & 3);
- }
- uint[] colorRet = new uint[w * h];
- for (int y = 0; y < h; ++y)
- {
- for (int x = 0; x < w; ++x)
- {
- int index = y * 4 + x;
- colorRet[y * w + x] = colors[tableIndices[index]];
- }
- }
- return colorRet;
- }
- private byte[] RGB565ToRGB8Array(ushort input)
- {
- uint r = (uint)(input & 0x1F);
- uint g = (uint)((input >> 5) & 0x3F);
- uint b = (uint)((input >> 11) & 0x1F);
- r = (r << 3) | (r >> 2);
- g = (g << 2) | (g >> 4);
- b = (b << 3) | (b >> 2);
- return new byte[] { (byte)r, (byte)g, (byte)b };
- }
- private uint ToOpaqueColor(byte[] clr)
- {
- return (uint)clr[2] | ((uint)clr[1] << 8) | ((uint)clr[0] << 16) | 0xFF000000;
- }
- private unsafe T Read<T>(BinaryReader reader) where T : struct
- {
- int size = Marshal.SizeOf(typeof(T));
- byte[] buffer = new byte[size];
- reader.Read(buffer, 0, size);
- fixed (byte* ptr = buffer)
- {
- return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T));
- }
- }
- private unsafe T[] Read<T>(T[] values, BinaryReader reader) where T : struct
- {
- int size = Marshal.SizeOf(typeof(T)) * values.Length;
- byte[] buffer = new byte[size];
- reader.Read(buffer, 0, size);
- GCHandle handle = GCHandle.Alloc(values, GCHandleType.Pinned);
- Marshal.Copy(buffer, 0, handle.AddrOfPinnedObject(), size);
- return values;
- }
- [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
- static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length);
- [StructLayout(LayoutKind.Sequential)]
- private struct TexHeader
- {
- public int signature;
- public int alwaysZero;
- public int width;
- public int height;
- public int depth;
- public int sides;
- public int mipCount;
- public int textureFormatIndex;
- }
- struct TextureFormatEntry
- {
- public int v1, v2, v3, v4, v5, v6, v7, v8, v9, blockSize, v11, format;
- public bool compressed;
- public TextureFormatEntry(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int v9,
- int blockSize, int v11, int format, bool compressed)
- {
- this.v1 = v1;
- this.v2 = v2;
- this.v3 = v3;
- this.v4 = v4;
- this.v5 = v5;
- this.v6 = v6;
- this.v7 = v7;
- this.v8 = v8;
- this.v9 = v9;
- this.blockSize = blockSize;
- this.v11 = v11;
- this.format = format;
- this.compressed = compressed;
- }
- };
- TextureFormatEntry[] FormatEntries =
- {
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, 0, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, 0, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 8, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
- new TextureFormatEntry(4, 3, 2, 4, 3, 2, 1, 0, 0, 8, 0, 1, true),
- new TextureFormatEntry(4, 3, 2, 4, 3, 2, 1, 0, 0, 16, 0, 2, true ),
- new TextureFormatEntry(4, 3, 2, 4, 3, 2, 1, 0, 0, 16, 0, 3, true ),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 8, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 16, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 2, 931135488, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 864026624, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 864026624, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
- new TextureFormatEntry(1, 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, -1, false),
- };
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment