private static void TpkTest() { //foreach (var f in Directory.GetFiles(@"C:\Games\Steam\steamapps\common\Dirt 2\frontend\ts", "*.tpk", SearchOption.TopDirectoryOnly)) //foreach (var f in Directory.GetFiles(@"C:\Games\Steam\steamapps\common\DiRT 3 Complete Edition\frontend\ts", "*.tpk", SearchOption.TopDirectoryOnly)) //foreach (var f in Directory.GetFiles(@"C:\Games\Steam\steamapps\common\F1 2012\frontend\ts", "*.tpk", SearchOption.TopDirectoryOnly)) foreach (var f in Directory.GetFiles(@"C:\Games\Steam\steamapps\common\F1 2014\frontend\ts", "*.tpk", SearchOption.TopDirectoryOnly)) { var fName = Path.GetFileName(f); using var fsi = File.Open(f, FileMode.Open, FileAccess.Read, FileShare.Read); var tpk = new TpkFile(); tpk.Read(fsi); if (!Enum.IsDefined(tpk.Format)) { Console.WriteLine($"{fName}\t frmt {tpk.Format}"); } if (tpk.Name != Path.GetFileNameWithoutExtension(f)) { Console.WriteLine($"{fName}\t name {tpk.Name}"); } if (tpk.Unk11 != 0) { Console.WriteLine($"{fName}\t u11 {tpk.Unk11}"); } if (tpk.Unk12 != 1.0) { Console.WriteLine($"{fName}\t u12 {tpk.Unk12}"); } } }
public static void FromDds(this TpkFile tpk, DdsFile dds) { tpk.Format = GetTpkImageFormat(dds); tpk.Width = dds.header.width; tpk.Height = dds.header.height; tpk.MipMapCount = dds.header.mipMapCount; tpk.Data = dds.bdata; }
public static DdsFile ToDds(this TpkFile tpk) { var dds = new DdsFile(); switch (tpk.Format) { case TpkImageFormat.Bgra: // BGRA little-endian dds.header.flags |= DdsHeader.Flags.DDSD_LINEARSIZE; dds.header.ddspf.flags |= DdsPixelFormat.Flags.DDPF_ALPHAPIXELS | DdsPixelFormat.Flags.DDPF_RGB; dds.header.ddspf.fourCC = 0; dds.header.ddspf.rGBBitCount = 32; dds.header.ddspf.bBitMask = 0xFF; dds.header.ddspf.gBitMask = 0xFF00; dds.header.ddspf.rBitMask = 0xFF0000; dds.header.ddspf.aBitMask = 0xFF000000; dds.header.pitchOrLinearSize = tpk.Width * tpk.Height * 4; break; case TpkImageFormat.Dxt1: dds.header.flags |= DdsHeader.Flags.DDSD_LINEARSIZE; dds.header.ddspf.flags |= DdsPixelFormat.Flags.DDPF_FOURCC; dds.header.ddspf.fourCC = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DXT1"), 0); dds.header.pitchOrLinearSize = Math.Max(tpk.Width * tpk.Height / 2, MinBc1LinearSize); break; case TpkImageFormat.Dxt3: dds.header.flags |= DdsHeader.Flags.DDSD_LINEARSIZE; dds.header.ddspf.flags |= DdsPixelFormat.Flags.DDPF_FOURCC; dds.header.ddspf.fourCC = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DXT3"), 0); dds.header.pitchOrLinearSize = Math.Max(tpk.Width * tpk.Height, MinBc2LinearSize); break; case TpkImageFormat.Dxt5: dds.header.flags |= DdsHeader.Flags.DDSD_LINEARSIZE; dds.header.ddspf.flags |= DdsPixelFormat.Flags.DDPF_FOURCC; dds.header.ddspf.fourCC = BitConverter.ToUInt32(Encoding.UTF8.GetBytes("DXT5"), 0); dds.header.pitchOrLinearSize = Math.Max(tpk.Width * tpk.Height, MinBc3LinearSize); break; default: throw new NotSupportedException($"Tpk format {tpk.Format} not supported."); } dds.header.width = tpk.Width; dds.header.height = tpk.Height; if (tpk.MipMapCount > 0) { dds.header.flags |= DdsHeader.Flags.DDSD_MIPMAPCOUNT; dds.header.mipMapCount = tpk.MipMapCount; dds.header.caps |= DdsHeader.Caps.DDSCAPS_MIPMAP | DdsHeader.Caps.DDSCAPS_COMPLEX; } dds.bdata = tpk.Data; return(dds); }
static int Main(string[] args) { PrintBanner(); if (args.Length < 1) { PrintUsage(); return(1); } string configFile = args[0]; ConfigFile config = new ConfigFile(); config.LoadFile(configFile, new string[] { "texture" }); FileInfo fileInfo = new FileInfo(configFile); Directory.SetCurrentDirectory(fileInfo.DirectoryName); string xName = config.GetValue("tpk", "xname"); ArrayList textures = new ArrayList(); int textureCount = config.GetCount("texture"); uint memoryOffset = 0; for (int i = 0; i < textureCount; i++) { DDS dds = new DDS(); string ddsfile = config.GetValue("texture", i, "file"); dds.Open(ddsfile); if ((dds.FormatFlags & DDS.DDSFormatFlags.DXT) == 0 || !(dds.FormatFourCC == DDS.DDSFormatFourCC.DXT1 || dds.FormatFourCC == DDS.DDSFormatFourCC.DXT3)) { throw new Exception("Currently only DXT1 and DXT3 textures are supported."); } bool hasAlpha = false; if (dds.FormatFourCC == DDS.DDSFormatFourCC.DXT3) { hasAlpha = true; } TpkTextureInfo texInfo = new TpkTextureInfo(); if (xName == null) { texInfo.TextureName = config.GetValue("texture", i, "name"); } else { texInfo.TextureName = xName + "_" + config.GetValue("texture", i, "name"); } texInfo.Hash = Hash(texInfo.TextureName); string usage = config.GetValue("texture", i, "usage"); if (usage != null) { usage = usage.ToLower(); } if (usage == "type1") { texInfo.Usage = 0x1B81E7B0; } else if (usage == "type2") { texInfo.Usage = 0x1DA6C8A6; } else { texInfo.Usage = 0x1A93CF; } bool flagA = config.GetValue("texture", i, "flaga") == "1"; texInfo.MemoryOffset = memoryOffset; texInfo.TextureLength = (uint)dds.Pitch; texInfo.MemoryPaletteOffset = texInfo.MemoryOffset + texInfo.TextureLength; texInfo.PaletteLength = 0; texInfo.PitchOrLinearSize = dds.Pitch; texInfo.Width = (ushort)dds.Width; texInfo.Height = (ushort)dds.Height; texInfo.D1 = 0x220000; texInfo.D1 += ((int)Math.Log((double)texInfo.Height, 2)) << 8; texInfo.D1 += ((int)Math.Log((double)texInfo.Width, 2)); texInfo.D2 = 0x10000; texInfo.D3 = hasAlpha ? 0x500 : 0x0; texInfo.D4 = hasAlpha ? (0x10201 - (flagA ? 0x1 : 0x0)) : (0x1000000 + (flagA ? 0x2000000 : 0x0)); texInfo.D5 = 0x100; texInfo.D6 = 0x0; texInfo.D7 = 0x1000000; texInfo.D8 = 0x100; texInfo.Alpha = hasAlpha ? 0x1 : 0x0; texInfo.D9 = 5; texInfo.D10 = 6; texInfo.D3DFormat = (int)dds.FormatFourCC; MemoryStream msTex = new MemoryStream(dds.Pitch + 0x9c + 0x10); BinaryWriter bwTex = new BinaryWriter(msTex); bwTex.Write((int)0x57574152); bwTex.Write((int)0x1001); bwTex.Write((int)(dds.Pitch + 0x9c)); bwTex.Write((int)(dds.Pitch + 0x9c + 0x10)); bwTex.Write(dds.Texture[0]); texInfo.Write(bwTex); byte[] texData = msTex.GetBuffer(); msTex.Close(); TextureInfo textureInfo = new TextureInfo(); textureInfo.Hash = texInfo.Hash; textureInfo.Length = (uint)texData.Length - 0x10; textureInfo.LengthCompressed = (uint)texData.Length; textureInfo.Data = texData; textures.Add(textureInfo); memoryOffset += texInfo.TextureLength + texInfo.PaletteLength; } textures.Sort(); int initialLen = 0xDC + textures.Count * (0x8 + 0x18); int paddingToData = 0x80 - ((initialLen + 8) % 0x80); int textureOffsBase = initialLen + 8 + paddingToData + 0x100; uint offs = (uint)textureOffsBase; foreach (TextureInfo ti in textures) { ti.Offset = offs; offs += ti.LengthCompressed; if ((offs % 0x40) != 0) { offs += 0x40 - (offs % 0x40); } } uint maxOffs = offs; TpkFile tpk = new TpkFile(); tpk.AddBlock(new TpkNull(0x30)); TpkBaseBlock head = new TpkBaseBlock(TpkChunk.TpkHead); TpkHeadFileInfo fi = new TpkHeadFileInfo(); fi.GlobalPath = config.GetValue("tpk", "pipelinepath"); if (fi.GlobalPath == null) { fi.GlobalPath = ""; } fi.FileHash = Hash(fi.GlobalPath); fi.TextureName = config.GetValue("tpk", "identifier"); if (fi.TextureName == null) { fi.TextureName = ""; } fi.Version = 5; head.AddBlock(fi); TpkHeadHash hashes = new TpkHeadHash(); hashes.Count = textures.Count; for (int i = 0; i < textures.Count; i++) { hashes[i] = (textures[i] as TextureInfo).Hash; } head.AddBlock(hashes); TpkHeadDataOffset tpkdo = new TpkHeadDataOffset(); for (int i = 0; i < textures.Count; i++) { TextureInfo ti = textures[i] as TextureInfo; TpkHeadDataOffset.DataOffsetStruct dos = new TpkHeadDataOffset.DataOffsetStruct(); dos.Flags = 0x100; dos.Hash = ti.Hash; dos.Length = ti.LengthCompressed; dos.RealLength = ti.Length; dos.Offset = ti.Offset; tpkdo[ti.Hash] = dos; } head.AddBlock(tpkdo); tpk.AddBlock(head); tpk.AddBlock(new TpkNull(paddingToData)); TpkBaseBlock data = new TpkBaseBlock(TpkChunk.TpkData); TpkDataHeadLink headlink = new TpkDataHeadLink(); headlink.Unknown1 = 1; headlink.FileHash = fi.FileHash; data.AddBlock(headlink); data.AddBlock(new TpkNull(0x50)); TpkDataRaw raw = new TpkDataRaw(); MemoryStream ms = new MemoryStream((int)maxOffs - textureOffsBase + 0x78); BinaryWriter msbw = new BinaryWriter(ms); for (int i = 0; i < textures.Count; i++) { TextureInfo ti = textures[i] as TextureInfo; msbw.Seek((int)ti.Offset - textureOffsBase + 0x78, SeekOrigin.Begin); msbw.Write(ti.Data); } /* * if (((ms.Position + 8) % 0x40) != 0) * { * msbw.Seek((int)ms.Position + 0x40 - (((int)ms.Position + 8) % 0x40), SeekOrigin.Begin); * msbw.Seek(-4, SeekOrigin.Current); * msbw.Write((int)0xAAAAAA); * } */ raw.SetDataRaw(ms.GetBuffer()); ms.Close(); data.AddBlock(raw); tpk.AddBlock(data); string save = config.GetValue("tpk", "output"); if (save == null) { save = "TEXTURES.BIN"; } tpk.Save(save); return(0); }
private static void Convert(string f) { var fileName = Path.GetFileName(f); var ext = Path.GetExtension(f); string magic; string xmlMagic; using (var fs = File.Open(f, FileMode.Open, FileAccess.Read, FileShare.Read)) { PkgBinaryReader reader = new PkgBinaryReader(fs); magic = reader.ReadString(4); // Skip first byte since BXMLBig starts with \0 causing empty string reader.Seek(1, SeekOrigin.Begin); xmlMagic = reader.ReadString(3); } if (xmlMagic == "\"Rr" || xmlMagic == "BXM") { using var fsi = File.Open(f, FileMode.Open, FileAccess.Read, FileShare.Read); XmlFile file = new XmlFile(fsi); using var fso = File.Open(f + ".xml", FileMode.Create, FileAccess.Write, FileShare.Read); file.Write(fso, XMLType.Text); Console.WriteLine("Success! XML converted."); } else if (magic == "LNGT") { using var fsi = File.Open(f, FileMode.Open, FileAccess.Read, FileShare.Read); LngFile file = new LngFile(fsi); using var fso = File.Open(f + ".xml", FileMode.Create, FileAccess.Write, FileShare.Read); file.WriteXml(fso); Console.WriteLine("Success! Lng converted."); } else if (magic == "!pkg") { using var fsi = File.Open(f, FileMode.Open, FileAccess.Read, FileShare.Read); PkgFile file = PkgFile.ReadPkg(fsi); using var fso = File.Open(f + ".json", FileMode.Create, FileAccess.Write, FileShare.Read); file.WriteJson(fso); Console.WriteLine("Success! Pkg converted."); } else if (ext == ".tpk") { using var fsi = File.Open(f, FileMode.Open, FileAccess.Read, FileShare.Read); var tpk = new TpkFile(); tpk.Read(fsi); Console.WriteLine($"Tpk name '{tpk.Name}', image format '{tpk.Format}'."); var dds = tpk.ToDds(); using var fso = File.Open(f + ".dds", FileMode.Create, FileAccess.Write, FileShare.Read); dds.Write(fso, -1); Console.WriteLine("Success! Tpk converted."); } else if (fileName.EndsWith(".tpk.dds")) { using var fsi = File.Open(f, FileMode.Open, FileAccess.Read, FileShare.Read); var dds = new DdsFile(fsi); var tpk = new TpkFile() { Name = fileName.Remove(fileName.IndexOf('.')) }; tpk.FromDds(dds); using var fso = File.Open(f + ".tpk", FileMode.Create, FileAccess.Write, FileShare.Read); tpk.Write(fso); Console.WriteLine("Success! DDS converted."); } else { bool isJSON = false; JsonException jsonEx = null; try { using var fsi = File.Open(f, FileMode.Open, FileAccess.Read, FileShare.Read); PkgFile pkgFile = PkgFile.ReadJson(fsi); using var fso = File.Open(f + ".pkg", FileMode.Create, FileAccess.Write, FileShare.Read); pkgFile.WritePkg(fso); Console.WriteLine("Success! JSON converted."); isJSON = true; } catch (JsonException e) { jsonEx = e; } if (!isJSON) { XmlDocument xmlDoc = new XmlDocument(); try { xmlDoc.Load(f); } catch (XmlException e) { throw new AggregateException("Could not determine the file type! Showing json, and xml errors: ", jsonEx, e); } if (xmlDoc.DocumentElement.Name == "language") { using var fsi = File.Open(f, FileMode.Open, FileAccess.Read, FileShare.Read); DataSet dataSet = new DataSet("language"); dataSet.ReadXml(fsi, XmlReadMode.ReadSchema); LngFile file = new LngFile(dataSet); using var fso = File.Open(f + ".lng", FileMode.Create, FileAccess.Write, FileShare.Read); file.Write(fso); Console.WriteLine("Success! XML converted."); } else { using var fsi = File.Open(f, FileMode.Open, FileAccess.Read, FileShare.Read); XmlFile file = new XmlFile(fsi); using var fso = File.Open(f + ".xml", FileMode.Create, FileAccess.Write, FileShare.Read); file.Write(fso); Console.WriteLine("Success! XML converted."); } } } }