public void Deserialize(Stream input) { ushort magic = input.ReadValueU16(); if (magic != 512) { throw new FormatException(); } this.Width = input.ReadValueU16(); this.Height = input.ReadValueU16(); ushort mipCount = input.ReadValueU16(); this.Flags = input.ReadValueEnum <Tdx.HeaderFlags>(); this.Format = input.ReadValueEnum <Tdx.D3DFormat>(); if ((this.Flags & Tdx.HeaderFlags.HasExtraData) == Tdx.HeaderFlags.HasExtraData) { uint length = input.ReadValueU32(); this.ExtraData = new byte[length]; input.Read(this.ExtraData, 0, this.ExtraData.Length); } if ((this.Flags & Tdx.HeaderFlags.Unknown12) == Tdx.HeaderFlags.Unknown12) { // ref#5 throw new FormatException(); } else { if ((this.Flags & Tdx.HeaderFlags.Unknown0) == Tdx.HeaderFlags.Unknown0) { // ref#6 throw new FormatException(); } if ((this.Flags & Tdx.HeaderFlags.Unknown1) == Tdx.HeaderFlags.Unknown1) { // ref#7 throw new FormatException(); } if (this.Width > 2048 || this.Height > 2048) { // ref#8 throw new FormatException(); } this.Mipmaps.Clear(); for (ushort i = 0; i < mipCount; i++) { var mip = new Tdx.Mipmap(); mip.Width = (ushort)Math.Max(1, this.Width >> i); mip.Height = (ushort)Math.Max(1, this.Height >> i); mip.Data = new byte[Math.Max(1, GetMipSize(this.Format, mip.Width, mip.Height))]; input.Read(mip.Data, 0, mip.Data.Length); this.Mipmaps.Add(mip); } } if (input.Position != input.Length) { throw new FormatException(); } }
public static void Main(string[] args) { bool showHelp = false; bool saveExtra = false; var options = new OptionSet() { { "e|extra", "save extra data if present when converting from TDX", v => saveExtra = v != null }, { "h|help", "show this message and exit", v => showHelp = v != null }, }; List <string> extra; try { extra = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extra.Count < 1 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_texture*", GetExecutableName()); Console.WriteLine("Convert a texture to / from Duels of the Planewalkers TDX format."); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } foreach (string inputPath in extra) { Console.WriteLine(inputPath); var extension = Path.GetExtension(inputPath); if (extension != null) { extension = extension.ToLowerInvariant(); } // convert from tdx if (extension == ".tdx") { Stream input = File.OpenRead(inputPath); var tdx = new TdxFile(); tdx.Deserialize(input); input.Close(); if (saveExtra == true && tdx.ExtraData != null) { using (var output = File.Create(Path.ChangeExtension(inputPath, "_extra.bin"))) { output.Write(tdx.ExtraData, 0, tdx.ExtraData.Length); } } if (tdx.Format == Tdx.D3DFormat.DXT1 || tdx.Format == Tdx.D3DFormat.DXT3 || tdx.Format == Tdx.D3DFormat.DXT5) { Native.Flags flags = 0; if (tdx.Format == Tdx.D3DFormat.DXT1) { flags |= Native.Flags.DXT1; } else if (tdx.Format == Tdx.D3DFormat.DXT3) { flags |= Native.Flags.DXT3; } else if (tdx.Format == Tdx.D3DFormat.DXT5) { flags |= Native.Flags.DXT5; } var decompressed = Native.DecompressImage( tdx.Mipmaps[0].Data, tdx.Mipmaps[0].Width, tdx.Mipmaps[0].Height, flags); var bitmap = MakeBitmapFromDXT( tdx.Mipmaps[0].Width, tdx.Mipmaps[0].Height, decompressed, true); bitmap.Save( Path.ChangeExtension(inputPath, ".png"), ImageFormat.Png); } else if (tdx.Format == Tdx.D3DFormat.A8R8G8B8) { var bitmap = MakeBitmapFromA8R8G8B8( tdx.Mipmaps[0].Width, tdx.Mipmaps[0].Height, tdx.Mipmaps[0].Data); bitmap.Save( Path.ChangeExtension(inputPath, ".png"), ImageFormat.Png); } else if (tdx.Format == Tdx.D3DFormat.A4R4G4B4) { var bitmap = MakeBitmapFromA4R4G4B4( tdx.Mipmaps[0].Width, tdx.Mipmaps[0].Height, tdx.Mipmaps[0].Data); bitmap.Save( Path.ChangeExtension(inputPath, ".png"), ImageFormat.Png); } else if (tdx.Format == Tdx.D3DFormat.X8R8G8B8) { var bitmap = MakeBitmapFromX8R8G8B8( tdx.Mipmaps[0].Width, tdx.Mipmaps[0].Height, tdx.Mipmaps[0].Data); bitmap.Save( Path.ChangeExtension(inputPath, ".png"), ImageFormat.Png); } else { throw new NotSupportedException("unsupported format " + tdx.Format.ToString()); } } // convert to tdx else { // just a crappy convert to A8R8G8B8 for now... using (var bitmap = new Bitmap(inputPath)) { var tdx = new TdxFile(); tdx.Width = (ushort)bitmap.Width; tdx.Height = (ushort)bitmap.Height; tdx.Flags = 0; tdx.Format = Tdx.D3DFormat.A8R8G8B8; var mip = new Tdx.Mipmap(); mip.Width = tdx.Width; mip.Height = tdx.Height; int stride = mip.Width * 4; var area = new Rectangle(0, 0, bitmap.Width, bitmap.Height); var buffer = new byte[mip.Height * stride]; var bitmapData = bitmap.LockBits(area, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); IntPtr scan = bitmapData.Scan0; for (int y = 0, o = 0; y < mip.Height; y++, o += stride) { Marshal.Copy(scan, buffer, o, stride); scan += bitmapData.Stride; } bitmap.UnlockBits(bitmapData); mip.Data = buffer; tdx.Mipmaps.Add(mip); using (var output = File.Create(Path.ChangeExtension(inputPath, ".TDX"))) { tdx.Serialize(output); } } } } }