static void ConvertDat(string path, string outBase = null) { if (outBase == null) { outBase = Path.GetDirectoryName(path); } Directory.CreateDirectory(outBase); using (Stream fs = Utils.CheckDecompress(File.OpenRead(path))) using (DatReader dat = new DatReader(fs)) { for (int i = 0; i < dat.EntriesCount; ++i) { using (MemoryStream subfile = new MemoryStream(dat.GetData(i))) { string outPath = Path.Combine(outBase, Path.GetFileName(path + $"_{i}.png")); Console.WriteLine(outPath); try { TxmConversion.ConvertTxmToPng(subfile, outPath); } catch (NotSupportedException) { File.WriteAllBytes(path + $"_{i}.txm", subfile.ToArray()); throw; } } } } }
static void ExtractTrm(string trmPath, string basePath = null) { if (basePath == null) { basePath = Path.ChangeExtension(trmPath, null); } else { basePath = Path.Combine(basePath, Path.GetFileNameWithoutExtension(trmPath)); } using DatReader dat = new DatReader(Utils.CheckDecompress(File.OpenRead(trmPath))); // First entry is texture DAT using DatReader txmDat = new DatReader(new MemoryStream(dat.GetData(0))); using ObjConverter converter = new ObjConverter(txmDat); string mtlPath = basePath + ".mtl"; string mtlName = Path.GetFileName(mtlPath); // Subsequent entries are train car DATs for (int i = 1; i < dat.EntriesCount; ++i) { using DatReader innerDat = new DatReader(new MemoryStream(dat.GetData(i))); // And within each train car DAT are PDBs for (int j = 0; j < innerDat.EntriesCount; ++j) { using MemoryStream ms = new MemoryStream(innerDat.GetData(j)); BinaryReader br = new BinaryReader(ms); Pdb pdb = new Pdb(); pdb.Read(br); using StreamWriter sw = File.CreateText($"{basePath}.{i}_{j}.obj"); sw.WriteLine($"mtllib {mtlName}"); sw.WriteLine(); converter.ConvertObj(pdb, sw); } } using (StreamWriter sw = File.CreateText(mtlPath)) { converter.ExportTextures(sw, basePath + "."); } }
static void ExtractMapAnim(string mapAnimPath, string basePath = null) { if (basePath == null) { basePath = Path.ChangeExtension(mapAnimPath, null); } else { basePath = Path.Combine(basePath, Path.GetFileNameWithoutExtension(mapAnimPath)); } using DatReader dat = new DatReader(Utils.CheckDecompress(File.OpenRead(mapAnimPath))); // Second entry is texture DAT using DatReader txmDat = new DatReader(new MemoryStream(dat.GetData(1))); using ObjConverter converter = new ObjConverter(txmDat); string mtlPath = basePath + ".mtl"; string mtlName = Path.GetFileName(mtlPath); // First entry is a collection of weird PDBs using DatReader pdbDat = new DatReader(new MemoryStream(dat.GetData(0))); for (int i = 0; i < pdbDat.EntriesCount; ++i) { using MemoryStream ms = new MemoryStream(pdbDat.GetData(i)); // This is a DAT, but we're going to pretend it's a normal PDB BinaryReader br = new BinaryReader(ms); Pdb pdb = new Pdb(); pdb.Read(br); using StreamWriter sw = File.CreateText($"{basePath}.{i}.obj"); sw.WriteLine($"mtllib {mtlName}"); sw.WriteLine(); converter.ConvertObj(pdb, sw); } using (StreamWriter sw = File.CreateText(mtlPath)) { converter.ExportTextures(sw, basePath + "."); } }
public SeDatReader(DatReader dat) { this.dat = dat ?? throw new ArgumentNullException(nameof(dat)); seToc = dat.GetData(0); seData = dat.GetData(1); using (MemoryStream ms = new MemoryStream(seToc)) { BinaryReader br = new BinaryReader(ms); while (true) { SeEntry entry = new SeEntry(); entry.Read(br); if (entry.DataOffset == -1 && entry.DataLength == -1) { break; } entries.Add(entry); } } }
static void ExtractBg(string bgPath, string basePath = null) { if (basePath == null) { basePath = Path.ChangeExtension(bgPath, null); } else { basePath = Path.Combine(basePath, Path.GetFileNameWithoutExtension(bgPath)); } DatReader dat = new DatReader(Utils.CheckDecompress(File.OpenRead(bgPath))); using ObjConverter converter = new ObjConverter(dat); string mtlPath = basePath + ".mtl"; string mtlName = Path.GetFileName(mtlPath); for (int i = 0; i < 3; ++i) { using MemoryStream ms = new MemoryStream(dat.GetData(i)); DatReader innerDat = new DatReader(ms); for (int j = 0; j < innerDat.EntriesCount; ++j) { using BinaryReader br = new BinaryReader(new MemoryStream(innerDat.GetData(j))); Tdb tdb = new Tdb(); tdb.Read(br); // Remap textures (only known for Windows version, PS2 todo when files obtained) if (i == 0) { tdb.Textures[0].DatIndex = 4; tdb.Textures[1].DatIndex = 3; } else { tdb.Textures[0].DatIndex = 5; } using StreamWriter sw = File.CreateText($"{basePath}.{i}_{j}.obj"); sw.WriteLine($"mtllib {mtlName}"); sw.WriteLine(); converter.ConvertObj(tdb, sw); } } using (StreamWriter sw = File.CreateText(mtlPath)) { converter.ExportTextures(sw, basePath + ".", true); } }
static void ExtractDat(string datPath, string outBase) { if (outBase == null) { outBase = Path.GetDirectoryName(datPath); } using (DatReader dat = new DatReader(Utils.CheckDecompress(File.OpenRead(datPath)))) { for (int i = 0; i < dat.EntriesCount; ++i) { string outPath = Path.Combine(outBase, Path.GetFileName(datPath + $"_{i}.bin")); File.WriteAllBytes(outPath, dat.GetData(i)); } } }
public void Read(Stream stream) { Encoding shiftJisEncoding = Encoding.GetEncoding(932); Clear(); DatReader dat = new DatReader(stream); using (MemoryStream ms = new MemoryStream(dat.GetData(0))) { BinaryReader br = new BinaryReader(ms); uint infoSize = br.ReadUInt32(); uint[] numChars = new uint[4]; // numChars[0] is dummy for (int i = 1; i < numChars.Length; ++i) { numChars[i] = br.ReadUInt32(); } byte[] chBytes = new byte[2]; for (int i = 1; i < numChars.Length; ++i) { using MemoryStream graphicsMs = new MemoryStream(dat.GetData(i)); BinaryReader graphicsBr = new BinaryReader(graphicsMs); var numCharInSection = numChars[i]; for (int j = 0; j < numCharInSection; ++j) { // Characters are stored as 16-bit little-endian values chBytes[1] = br.ReadByte(); chBytes[0] = br.ReadByte(); char ch = shiftJisEncoding.GetChars(chBytes)[0]; byte[] pixels = graphicsBr.ReadBytes((WIDTH * HEIGHT + PADDING) / 2); // 4bpp characterMap.Add(ch, pixels); } } } }
static void ExtractPdb(string pdbPath, string txmPath, string basePath = null, bool forceDirect = false) { if (basePath == null) { basePath = Path.ChangeExtension(pdbPath, null); } else { basePath = Path.Combine(basePath, Path.GetFileNameWithoutExtension(pdbPath)); } DatReader dat = new DatReader(Utils.CheckDecompress(File.OpenRead(pdbPath))); using DatReader txmDat = new DatReader(Utils.CheckDecompress(File.OpenRead(txmPath))); using ObjConverter converter = new ObjConverter(txmDat); string mtlPath = basePath + ".mtl"; string mtlName = Path.GetFileName(mtlPath); for (int i = 0; i < dat.EntriesCount; ++i) { using MemoryStream ms = new MemoryStream(dat.GetData(i)); BinaryReader br = new BinaryReader(ms); Pdb pdb = new Pdb(); pdb.Read(br); using StreamWriter sw = File.CreateText($"{basePath}.{i}.obj"); sw.WriteLine($"mtllib {mtlName}"); sw.WriteLine(); converter.ConvertObj(pdb, sw); } using (StreamWriter sw = File.CreateText(mtlPath)) { converter.ExportTextures(sw, basePath + ".", forceDirect); } }
static void ReplaceDatImages(string srcDatPath, string destDatPath, string replacementList) { List <string> tempPaths = new List <string>(); try { using (DatReader dat = new DatReader(File.OpenRead(srcDatPath))) { DatBuilder builder = new DatBuilder(dat); using (StreamReader sr = File.OpenText(replacementList)) { while (!sr.EndOfStream) { var line = sr.ReadLine().Trim(); if (line.Length == 0 || line.StartsWith("#")) { continue; } var lineSplit = line.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries); if (lineSplit.Length != 2) { throw new InvalidDataException($"Invalid line \"{line}\"."); } if (!int.TryParse(lineSplit[0], out var imageIndex)) { throw new InvalidDataException($"Invalid index on line \"{line}\"."); } byte level = 1; ushort bufferBase = 0; ushort paletteBufferBase = 0; if (imageIndex < dat.EntriesCount) { using (MemoryStream ms = new MemoryStream(dat.GetData(imageIndex))) { TxmHeader txm = new TxmHeader(); txm.Read(new BinaryReader(ms)); level = (byte)(txm.Misc & 0x0f); bufferBase = txm.ImageBufferBase; paletteBufferBase = txm.ClutBufferBase; } } string tempPath = Path.GetTempFileName(); tempPaths.Add(tempPath); using (FileStream fs = File.Create(tempPath)) { TxmConversion.ConvertImageToTxm(lineSplit[1], fs, level, bufferBase, paletteBufferBase); } builder.ReplacementEntries.Add(new DatBuilder.ReplacementEntry { Index = imageIndex, SourceFile = tempPath }); } } using (FileStream fs = File.Create(destDatPath)) { builder.Build(fs); } } } finally { foreach (var path in tempPaths) { File.Delete(path); } } }
public void ExportTextures(StreamWriter mtlWriter, string outputPath, bool forceDirect = false) { if (disposedValue) { throw new ObjectDisposedException(GetType().FullName); } if (textureDat == null) { throw new InvalidOperationException("No texture pack supplied."); } int i = 0; numWrittenTextures = 0; foreach (var pair in textureCache.OrderBy(p => p.Key)) { string pngPath = $"{outputPath}{i}.png"; string alphaPath = $"{outputPath}{i}_alpha.png"; TxmHeader textureTxm = pair.Value; int txmIndex = (int)(pair.Key >> 32); using (var txmMs = new MemoryStream(textureDat.GetData(txmIndex))) { BinaryReader txmBr = new BinaryReader(txmMs); TxmHeader pakTxm = new TxmHeader(); pakTxm.Read(txmBr); Image <Rgba32> img = null; try { // Check if TXM is already suitable if (forceDirect || /*pakTxm.ImageSourcePixelFormat == textureTxm.ImageSourcePixelFormat &&*/ pakTxm.ImageBufferBase == textureTxm.ImageBufferBase && pakTxm.ClutPixelFormat == textureTxm.ClutPixelFormat && pakTxm.ClutBufferBase == textureTxm.ClutBufferBase) { // Use TXM as-is txmMs.Seek(0, SeekOrigin.Begin); if (new string(txmBr.ReadChars(4)) == "DAT\0") { // Unwrap DAT txmMs.Seek(0, SeekOrigin.Begin); using (DatReader txmDat = new DatReader(txmMs)) { if (txmDat.EntriesCount != 1) { throw new InvalidDataException("Nested texture DAT contains more than one file."); } using (MemoryStream innerStream = new MemoryStream(txmDat.GetData(0))) { img = TxmConversion.ConvertTxmToImage(innerStream); } } } else { txmMs.Seek(0, SeekOrigin.Begin); img = TxmConversion.ConvertTxmToImage(txmMs); // Dump palette //if (pakTxm.ClutPixelFormat != TxmPixelFormat.None) //{ // txmMs.Seek(0x10, SeekOrigin.Begin); // using (var palette = TxmConversion.ConvertTxmRgba32(txmBr, pakTxm.ClutWidth, pakTxm.ClutHeight)) // { // palette.SaveAsPng($"palette_{numWrittenTextures}.png"); // } //} } } else { // Generate new TXM using (MemoryStream ms = new MemoryStream()) { BinaryWriter bw = new BinaryWriter(ms); textureTxm.Write(bw); CopyTexelsClut(txmBr, bw, pakTxm, textureTxm); CopyTexels(txmBr, bw, pakTxm, textureTxm); bw.Flush(); ms.Seek(0, SeekOrigin.Begin); img = TxmConversion.ConvertTxmToImage(ms); } } // Save out color texture using (var img24bpp = img.CloneAs <Rgb24>()) { img24bpp.SaveAsPng(pngPath); } // Extract alpha channel as a separate image using (var alphaImg = new Image <L8>(img.Width, img.Height)) { for (int y = 0; y < alphaImg.Height; ++y) { var srcSpan = img.GetPixelRowSpan(y); var destSpan = alphaImg.GetPixelRowSpan(y); for (int x = 0; x < alphaImg.Width; ++x) { var srcAlpha = srcSpan[x].A; destSpan[x] = new L8(srcAlpha); } } alphaImg.SaveAsPng(alphaPath); } } finally { if (img != null) { img.Dispose(); } } } mtlWriter.WriteLine($"newmtl tex_{pair.Key:x12}"); mtlWriter.WriteLine("Kd 0.80000000 0.80000000 0.80000000"); mtlWriter.WriteLine("Ka 0 0 0"); mtlWriter.WriteLine("Ke 0 0 0"); mtlWriter.WriteLine("Ks 0 0 0"); mtlWriter.WriteLine("d 1"); mtlWriter.WriteLine("illum 2"); mtlWriter.WriteLine($"map_Kd {Path.GetFileName(pngPath)}"); mtlWriter.WriteLine($"map_d {Path.GetFileName(alphaPath)}"); mtlWriter.WriteLine(); ++i; ++numWrittenTextures; } }