725 lines
30 KiB
C#
725 lines
30 KiB
C#
using LibDgf;
|
|
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;
|
|
using SixLabors.ImageSharp.PixelFormats;
|
|
using SixLabors.ImageSharp.Processing;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Text;
|
|
using Path = System.IO.Path;
|
|
|
|
namespace DgfTxmConvert
|
|
{
|
|
class Program
|
|
{
|
|
const string ETC1TOOL_PATH = @"etc1tool.exe";
|
|
|
|
static List<IAlImageConverter> imageConverters;
|
|
|
|
static int Main(string[] args)
|
|
{
|
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
|
imageConverters = new List<IAlImageConverter>
|
|
{
|
|
new PkmConverter(),
|
|
//new KtxConverter(),
|
|
new PngConverter(),
|
|
};
|
|
|
|
var app = new CommandLineApplication
|
|
{
|
|
Name = Path.GetFileName(Environment.GetCommandLineArgs()[0]),
|
|
FullName = "DDG Final TXM Converter"
|
|
};
|
|
|
|
app.Command("convert-dat", config =>
|
|
{
|
|
config.FullName = "Convert DAT to images";
|
|
config.Description = "Converts each individual TXM in a DAT into PNGs.";
|
|
|
|
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(() =>
|
|
{
|
|
ConvertDat(datPathArg.Value, outBaseArg.Value);
|
|
});
|
|
});
|
|
|
|
app.Command("convert-txm", config =>
|
|
{
|
|
config.FullName = "Convert TXM to image";
|
|
config.Description = "Converts TXM to PNG.";
|
|
|
|
var txmPathArg = config.Argument("txmPath", "Path of the TXM to convert").IsRequired();
|
|
txmPathArg.Accepts().ExistingFile();
|
|
var outPathArg = config.Argument("outPath", "Path of converted PNG");
|
|
outPathArg.Accepts().LegalFilePath();
|
|
config.HelpOption();
|
|
|
|
config.OnExecute(() =>
|
|
{
|
|
ConvertTxm(txmPathArg.Value, outPathArg.Value);
|
|
});
|
|
});
|
|
|
|
app.Command("replace-dat", config =>
|
|
{
|
|
config.FullName = "Replace image in DAT";
|
|
config.Description = "Converts list of images and replaces entries in DAT file";
|
|
|
|
var srcDatPath = config.Argument("srcDatPath", "Path of the source DAT").IsRequired();
|
|
srcDatPath.Accepts().ExistingFile();
|
|
var listPath = config.Argument("listPath", "Path of the image replacement list").IsRequired();
|
|
listPath.Accepts().ExistingFile();
|
|
var destDatPath = config.Argument("destDatPath", "Path to output DAT to").IsRequired();
|
|
listPath.Accepts().LegalFilePath();
|
|
config.HelpOption();
|
|
|
|
config.OnExecute(() =>
|
|
{
|
|
ReplaceDatImages(srcDatPath.Value, destDatPath.Value, listPath.Value);
|
|
});
|
|
});
|
|
|
|
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();
|
|
var forceTexDirectOption = config.Option("--forceTexDirect", "Convert TXM as is without trying PS2 texture unpack", CommandOptionType.NoValue);
|
|
config.HelpOption();
|
|
|
|
config.OnExecute(() =>
|
|
{
|
|
ExtractPdb(pdbPathArg.Value, txmPathArg.Value, outBaseArg.Value, forceTexDirectOption.HasValue());
|
|
});
|
|
});
|
|
|
|
app.Command("convert-bg", config =>
|
|
{
|
|
config.FullName = "Converts sky dome";
|
|
config.Description = "Converts sky dome.";
|
|
|
|
var bgPathArg = config.Argument("bgPath", "Path of the sky dome pack to extract").IsRequired();
|
|
bgPathArg.Accepts().ExistingFile();
|
|
var outBaseArg = config.Argument("outBase", "Directory to write converted files");
|
|
outBaseArg.Accepts().LegalFilePath();
|
|
config.HelpOption();
|
|
|
|
config.OnExecute(() =>
|
|
{
|
|
ExtractBg(bgPathArg.Value, outBaseArg.Value);
|
|
});
|
|
});
|
|
|
|
app.Command("convert-mapanim", config =>
|
|
{
|
|
config.FullName = "Converts mapanim files";
|
|
config.Description = "Converts mapanim models.";
|
|
|
|
var mapAnimPathArg = config.Argument("mapAnimPathArg", "Path of the mapanim model to extract").IsRequired();
|
|
mapAnimPathArg.Accepts().ExistingFile();
|
|
var outBaseArg = config.Argument("outBase", "Directory to write converted files");
|
|
outBaseArg.Accepts().LegalFilePath();
|
|
config.HelpOption();
|
|
|
|
config.OnExecute(() =>
|
|
{
|
|
ExtractMapAnim(mapAnimPathArg.Value, outBaseArg.Value);
|
|
});
|
|
});
|
|
|
|
app.VersionOptionFromAssemblyAttributes(System.Reflection.Assembly.GetExecutingAssembly());
|
|
app.HelpOption();
|
|
|
|
app.OnExecute(() =>
|
|
{
|
|
app.ShowHelp();
|
|
return 1;
|
|
});
|
|
|
|
try
|
|
{
|
|
return app.Execute(args);
|
|
}
|
|
catch (CommandParsingException ex)
|
|
{
|
|
Console.Error.WriteLine(ex.Message);
|
|
return 1;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.Error.WriteLine("Error while processing: {0}", ex);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
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<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);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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 BulkConvertDat(string inPath, string filter, bool recursive)
|
|
{
|
|
foreach (var path in Directory.GetFiles(inPath, filter, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
|
|
{
|
|
ConvertDat(path);
|
|
}
|
|
}
|
|
|
|
static void ConvertTxm(string path, string outPath = null)
|
|
{
|
|
using (Stream fs = Utils.CheckDecompress(File.OpenRead(path)))
|
|
{
|
|
if (outPath == null) outPath = Path.ChangeExtension(path, ".png");
|
|
TxmConversion.ConvertTxmToPng(fs, outPath);
|
|
}
|
|
}
|
|
|
|
static void BulkConvertTxm(string inPath, string filter, bool recursive)
|
|
{
|
|
foreach (var path in Directory.GetFiles(inPath, filter, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
|
|
{
|
|
string outPath = Path.ChangeExtension(path, ".png");
|
|
Console.WriteLine(outPath);
|
|
ConvertTxm(path);
|
|
}
|
|
}
|
|
|
|
static void BulkConvertAtx(string inPath, string filter, bool recursive)
|
|
{
|
|
foreach (var path in Directory.GetFiles(inPath, filter, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
|
|
{
|
|
Console.WriteLine(path);
|
|
using (var fs = Utils.CheckDecompress(File.OpenRead(path)))
|
|
{
|
|
var tex = new AlTexture();
|
|
tex.Read(new BinaryReader(fs));
|
|
|
|
var img = new AlImage();
|
|
using (Stream ms = Utils.CheckDecompress(new MemoryStream(tex.ImageData)))
|
|
{
|
|
img.Read(new BinaryReader(ms));
|
|
ConvertAig(img, path);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void BulkConvertAtxMulti(string inPath, string filter, bool recursive)
|
|
{
|
|
foreach (var path in Directory.GetFiles(inPath, filter, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
|
|
{
|
|
using (var fs = Utils.CheckDecompress(File.OpenRead(path)))
|
|
{
|
|
var tex = new AlTexture();
|
|
tex.Read(new BinaryReader(fs));
|
|
|
|
if (tex.ChildTextures.Count < 2) continue;
|
|
Console.WriteLine(path);
|
|
|
|
var img = new AlImage();
|
|
using (Stream ms = Utils.CheckDecompress(new MemoryStream(tex.ImageData)))
|
|
{
|
|
img.Read(new BinaryReader(ms));
|
|
if (img.PixelFormat != "BGRA")
|
|
{
|
|
Console.WriteLine("Not BGRA, skipping");
|
|
continue;
|
|
}
|
|
|
|
using (MemoryStream ims = new MemoryStream(img.Mipmaps[0]))
|
|
using (var imgConv = PngConverter.ConvertBgra32(new BinaryReader(ims), (int)img.Width, (int)img.Height))
|
|
{
|
|
foreach (var child in tex.ChildTextures)
|
|
{
|
|
// First mip only
|
|
var bounds = child.Bounds[0];
|
|
using (var childImage = new Image<Bgra32>(bounds.W, bounds.H))
|
|
{
|
|
childImage.Mutate(ctx => ctx.DrawImage(imgConv, new Point(-bounds.X, -bounds.Y), 1f));
|
|
childImage.SaveAsPng($"{Path.ChangeExtension(path, null)}_{child.Id:x8}.png");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void BulkConvertAtxToPng(string inPath, string filter, bool recursive)
|
|
{
|
|
foreach (var path in Directory.GetFiles(inPath, filter, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
|
|
{
|
|
Console.WriteLine(path);
|
|
string fileExtension;
|
|
|
|
// Export the texture (probably KTX)
|
|
using (var fs = Utils.CheckDecompress(File.OpenRead(path)))
|
|
{
|
|
var tex = new AlTexture();
|
|
tex.Read(new BinaryReader(fs));
|
|
|
|
var img = new AlImage();
|
|
using (Stream ms = Utils.CheckDecompress(new MemoryStream(tex.ImageData)))
|
|
{
|
|
img.Read(new BinaryReader(ms));
|
|
fileExtension = ConvertAig(img, path);
|
|
}
|
|
}
|
|
|
|
if (fileExtension != ".pkm") continue;
|
|
|
|
// Convert main texture to PNG
|
|
string mainPath = Path.ChangeExtension(path, fileExtension);
|
|
var startInfo = new ProcessStartInfo(ETC1TOOL_PATH);
|
|
startInfo.ArgumentList.Add(mainPath);
|
|
startInfo.ArgumentList.Add("--decode");
|
|
startInfo.CreateNoWindow = false;
|
|
startInfo.UseShellExecute = false;
|
|
Process.Start(startInfo).WaitForExit();
|
|
|
|
// Convert alpha texture if present
|
|
string altPath = $"{Path.ChangeExtension(path, null)}_alt{fileExtension}";
|
|
if (File.Exists(altPath))
|
|
{
|
|
startInfo = new ProcessStartInfo(ETC1TOOL_PATH);
|
|
startInfo.ArgumentList.Add(altPath);
|
|
startInfo.ArgumentList.Add("--decode");
|
|
startInfo.CreateNoWindow = false;
|
|
startInfo.UseShellExecute = false;
|
|
Process.Start(startInfo).WaitForExit();
|
|
|
|
var mainPngPath = Path.ChangeExtension(mainPath, ".png");
|
|
var altPngPath = Path.ChangeExtension(altPath, ".png");
|
|
|
|
using (var mainImg = Image.Load<Rgb24>(mainPngPath))
|
|
using (var altImg = Image.Load<Rgb24>(altPngPath))
|
|
{
|
|
using (var mergedImg = MergeAlpha(mainImg, altImg))
|
|
using (FileStream newFs = File.Create(mainPngPath))
|
|
{
|
|
mergedImg.SaveAsPng(newFs);
|
|
}
|
|
}
|
|
|
|
File.Delete(altPngPath);
|
|
File.Delete(altPath);
|
|
}
|
|
|
|
File.Delete(mainPath);
|
|
}
|
|
}
|
|
|
|
static Image<Rgba32> MergeAlpha(Image<Rgb24> main, Image<Rgb24> alpha)
|
|
{
|
|
var newImg = new Image<Rgba32>(main.Width, main.Height);
|
|
for (int y = 0; y < newImg.Height; ++y)
|
|
{
|
|
var newRow = newImg.GetPixelRowSpan(y);
|
|
var mainRow = main.GetPixelRowSpan(y);
|
|
var alphaRow = alpha.GetPixelRowSpan(y);
|
|
for (int x = 0; x < newImg.Width; ++x)
|
|
{
|
|
var mainPix = mainRow[x];
|
|
var alphaPix = alphaRow[x];
|
|
newRow[x] = new Rgba32(mainPix.R, mainPix.G, mainPix.B, alphaPix.R);
|
|
}
|
|
}
|
|
return newImg;
|
|
}
|
|
|
|
static void BulkConvertAig(string inPath, string filter, bool recursive)
|
|
{
|
|
foreach (var path in Directory.GetFiles(inPath, filter, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
|
|
{
|
|
Console.WriteLine(path);
|
|
using (var fs = Utils.CheckDecompress(File.OpenRead(path)))
|
|
{
|
|
var img = new AlImage();
|
|
img.Read(new BinaryReader(fs));
|
|
ConvertAig(img, path);
|
|
}
|
|
}
|
|
}
|
|
|
|
static string ConvertAig(AlImage img, string path)
|
|
{
|
|
foreach (var converter in imageConverters)
|
|
{
|
|
if (converter.CanConvert(img.PixelFormat))
|
|
{
|
|
string outPath = Path.ChangeExtension(path, converter.FileExtension);
|
|
using (FileStream ofs = File.Create(outPath))
|
|
{
|
|
converter.ConvertFromAl(img, ofs);
|
|
}
|
|
if (converter.HasAlternativeFile(img))
|
|
{
|
|
outPath = Path.ChangeExtension(path, null);
|
|
outPath = $"{outPath}_alt{converter.FileExtension}";
|
|
using (FileStream ofs = File.Create(outPath))
|
|
{
|
|
converter.ConvertFromAlAlt(img, ofs);
|
|
}
|
|
}
|
|
return converter.FileExtension;
|
|
}
|
|
}
|
|
|
|
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, 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 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 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 + ".");
|
|
}
|
|
}
|
|
}
|
|
}
|