From 1c07e44a004a5d474cf324469839f280c6e0013c Mon Sep 17 00:00:00 2001 From: Yukai Li Date: Wed, 17 Mar 2021 03:22:29 -0600 Subject: [PATCH] Add mesh conversion and kanji, DAT extraction commands --- DgfTxmConvert/DgfTxmConvert.csproj | 1 + DgfTxmConvert/Program.cs | 190 ++++++++++++++++++++++++++++- README.md | 5 + 3 files changed, 194 insertions(+), 2 deletions(-) diff --git a/DgfTxmConvert/DgfTxmConvert.csproj b/DgfTxmConvert/DgfTxmConvert.csproj index c6c02a6..3204f83 100644 --- a/DgfTxmConvert/DgfTxmConvert.csproj +++ b/DgfTxmConvert/DgfTxmConvert.csproj @@ -9,6 +9,7 @@ + diff --git a/DgfTxmConvert/Program.cs b/DgfTxmConvert/Program.cs index 65660f3..67a9e10 100644 --- a/DgfTxmConvert/Program.cs +++ b/DgfTxmConvert/Program.cs @@ -3,7 +3,10 @@ using LibDgf.Aqualead.Image; using LibDgf.Aqualead.Image.Conversion; using LibDgf.Aqualead.Texture; using LibDgf.Dat; +using LibDgf.Font; using LibDgf.Graphics; +using LibDgf.Graphics.Mesh; +using LibDgf.Mesh; using LibDgf.Txm; using McMaster.Extensions.CommandLineUtils; using SixLabors.ImageSharp; @@ -13,6 +16,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Text; using Path = System.IO.Path; namespace DgfTxmConvert @@ -25,6 +29,7 @@ namespace DgfTxmConvert static int Main(string[] args) { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); imageConverters = new List { new PkmConverter(), @@ -91,6 +96,78 @@ namespace DgfTxmConvert }); }); + app.Command("dump-font", config => + { + config.FullName = "Dump kanji font"; + config.Description = "Extracts all characters from kanji font pack."; + + var pakPath = config.Argument("pakPath", "Path of the kanji pack").IsRequired(); + pakPath.Accepts().ExistingFile(); + var txmPath = config.Argument("txmPath", "Path of the kana TXM").IsRequired(); + txmPath.Accepts().ExistingFile(); + var outputPath = config.Argument("outputPath", "Path of directory to extract character images to"); + txmPath.Accepts().LegalFilePath(); + config.HelpOption(); + + config.OnExecute(() => + { + ExtractFontPack(pakPath.Value, txmPath.Value, outputPath.Value); + }); + }); + + app.Command("extract-dat", config => + { + config.FullName = "Extracts DAT"; + config.Description = "Extracts files from DAT."; + + var datPathArg = config.Argument("datPath", "Path of the DAT to extract").IsRequired(); + datPathArg.Accepts().ExistingFile(); + var outBaseArg = config.Argument("outBase", "Directory to write extracted files"); + outBaseArg.Accepts().LegalFilePath(); + config.HelpOption(); + + config.OnExecute(() => + { + ExtractDat(datPathArg.Value, outBaseArg.Value); + }); + }); + + app.Command("convert-trm", config => + { + config.FullName = "Converts TRM"; + config.Description = "Converts train models."; + + var trmPathArg = config.Argument("trmPath", "Path of the train model to extract").IsRequired(); + trmPathArg.Accepts().ExistingFile(); + var outBaseArg = config.Argument("outBase", "Directory to write converted files"); + outBaseArg.Accepts().LegalFilePath(); + config.HelpOption(); + + config.OnExecute(() => + { + ExtractTrm(trmPathArg.Value, outBaseArg.Value); + }); + }); + + app.Command("convert-pdb", config => + { + config.FullName = "Converts PDB"; + config.Description = "Converts PDB models."; + + var pdbPathArg = config.Argument("pdbPath", "Path of the model pack to extract").IsRequired(); + pdbPathArg.Accepts().ExistingFile(); + var txmPathArg = config.Argument("txmPath", "Path of the associated texture pack").IsRequired(); + txmPathArg.Accepts().ExistingFile(); + var outBaseArg = config.Argument("outBase", "Directory to write converted files"); + outBaseArg.Accepts().LegalFilePath(); + config.HelpOption(); + + config.OnExecute(() => + { + ExtractPdb(pdbPathArg.Value, txmPathArg.Value, outBaseArg.Value); + }); + }); + app.VersionOptionFromAssemblyAttributes(System.Reflection.Assembly.GetExecutingAssembly()); app.HelpOption(); @@ -116,6 +193,19 @@ namespace DgfTxmConvert } } + 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)); + } + } + } + static void ReplaceDatImages(string srcDatPath, string destDatPath, string replacementList) { List tempPaths = new List(); @@ -137,8 +227,8 @@ namespace DgfTxmConvert throw new InvalidDataException($"Invalid index on line \"{line}\"."); byte level = 1; - short bufferBase = 0; - short paletteBufferBase = 0; + ushort bufferBase = 0; + ushort paletteBufferBase = 0; if (imageIndex < dat.EntriesCount) { @@ -419,5 +509,101 @@ namespace DgfTxmConvert throw new Exception($"Cannot find converter for {img.PixelFormat}"); } + + static void ExtractFontPack(string pakPath, string txmPath, string basePath) + { + if (basePath == null) basePath = pakPath + "_extracted"; + using (Stream fs = Utils.CheckDecompress(File.OpenRead(txmPath))) + using (Stream datFs = Utils.CheckDecompress(File.OpenRead(pakPath))) + { + var fontTxmHeader = new TxmHeader(); + BinaryReader br = new BinaryReader(fs); + fontTxmHeader.Read(br); + var palette = TxmConversion.ReadRgba32Palette(br, fontTxmHeader.ClutWidth, fontTxmHeader.ClutHeight); + + var fontPak = new FontPack(); + fontPak.Read(datFs); + Directory.CreateDirectory(basePath); + + foreach (var ch in fontPak.Characters) + { + using MemoryStream ms = new MemoryStream(fontPak[ch]); + BinaryReader charBr = new BinaryReader(ms); + using (var img = TxmConversion.ConvertTxmIndexed4bpp(charBr, 24, 22, palette)) + { + img.SaveAsPng(Path.Combine(basePath, $"{ch}.png")); + } + } + } + } + + 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 ExtractPdb(string pdbPath, string txmPath, string basePath = null) + { + 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 + "."); + } + } } } diff --git a/README.md b/README.md index 8a02845..3399850 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Usage The following commands are available. For arguments please use the `--help` option. +- `extract-dat`: Unpacks files from .DAT container as-is. - `convert-dat`: Unpacks a .DAT container of textures and converts everything to PNG. - `convert-txm`: Converts a single .TXM file to PNG. @@ -19,6 +20,10 @@ option. Requires a text file with a line for each texture to be replaced, consisting of the index number and the path to the corresponding image (can be relative to working directory). +- `dump-font`: Extracts characters from kanji font pack. +- `convert-trm`: Converts train model file contents to Wavefront OBJ models. +- `convert-pdb`: Converts other model files to Wavefront OBJ models. Note the + corresponding texture DAT needs to be supplied as well. Other -----