From 43ea3a532c589fdcefb1ea6afa15de3a918bd4a7 Mon Sep 17 00:00:00 2001 From: Ulysses Wu Date: Tue, 17 Sep 2024 02:15:19 +0800 Subject: [PATCH] working on Spr color --- FreeMote.PsBuild/PsbCompiler.cs | 4 +- FreeMote.PsBuild/PsbDecompiler.cs | 5 + FreeMote.Psb/Psb.cs | 2 +- FreeMote.Psb/SprPainter.cs | 158 ++++++++++++++++++++++++++ FreeMote.Psb/Types/M2Types.cs | 137 +++++++++++++++-------- FreeMote.Tests/PsBuildTest.cs | 177 +++++++++++++++++++----------- FreeMote/Consts.cs | 5 + 7 files changed, 376 insertions(+), 112 deletions(-) create mode 100644 FreeMote.Psb/SprPainter.cs diff --git a/FreeMote.PsBuild/PsbCompiler.cs b/FreeMote.PsBuild/PsbCompiler.cs index e12e0df..1f84e96 100644 --- a/FreeMote.PsBuild/PsbCompiler.cs +++ b/FreeMote.PsBuild/PsbCompiler.cs @@ -245,6 +245,8 @@ public static (PSB Psb, Dictionary Context) LoadPsbAndContextFro //Parse PSB psb = Parse(File.ReadAllText(inputPath), version ?? 3); + psb.FilePath = inputPath; + //Link Dictionary context = null; if (!string.IsNullOrWhiteSpace(inputResJson)) @@ -311,7 +313,7 @@ internal static PSB Parse(string json, ushort version) { PSB psb = new PSB(version) { - Encoding = Encoding + Encoding = Encoding, }; var converter = new PsbJsonConverter(); var j = json.TrimStart(); diff --git a/FreeMote.PsBuild/PsbDecompiler.cs b/FreeMote.PsBuild/PsbDecompiler.cs index f49247d..39840f3 100644 --- a/FreeMote.PsBuild/PsbDecompiler.cs +++ b/FreeMote.PsBuild/PsbDecompiler.cs @@ -825,6 +825,11 @@ public static void ExtractArchive(string filePath, string key, Dictionary _textures = new Dictionary(); + + //palette: each single line is a palette + + public SprPainter(PSB sprData, string basePath) + { + SprData = sprData; + BasePath = basePath; + } + + private void Collect() + { + if (JsonMode) + { + //read images from BasePath\__ddd.psb.m\*.png + var dirs = Directory.GetDirectories(BasePath, "*.psb.m", SearchOption.TopDirectoryOnly); + foreach (var dir in dirs) + { + var png = Path.Combine(dir, "0.png"); + if (File.Exists(png)) + { + var dirName = Path.GetFileName(dir); + try + { + if(int.TryParse(dirName.Substring(dirName.IndexOf('.') - IdWidth, IdWidth), out int number)) + { + _textures.Add(number, new Bitmap(png)); + } + } + catch (Exception ex) + { + Logger.LogWarn($"Error processing {dirName}: {ex.Message}"); + } + } + } + } + else + { + Logger.LogError("JsonMode is the only supported mode for now."); + // var files = Directory.GetFiles(BasePath, "*.psb*", SearchOption.AllDirectories); + // foreach (var file in files) + // { + // var fileName = Path.GetFileName(file); + // var extension = Path.GetExtension(file).ToLowerInvariant(); + + // if(extension == ".m" || extension == ".psb") + // { + // try{ + // if(int.TryParse(fileName.Substring(2, fileName.IndexOf('.') - 2), out int number)) + // { + // PSB psb = new PSB(file); + // //TODO: + // } + // } + // catch (Exception ex) + // { + // Logger.LogWarn($"Error processing {fileName}: {ex.Message}"); + // } + // } + + // } + } + } + + public Dictionary Draw() + { + var result = new Dictionary(); + if (!JsonMode) + { + Logger.LogError("JsonMode is the only supported mode for now."); + return result; + } + + Collect(); + + var sprDataList = SprData.Objects["spr_data"] as PsbList; + for (int i = 0; i < sprDataList.Count; i++) + { + var sprImage = sprDataList[i] as PsbDictionary; + var org = sprImage.Children("org") as PsbList; + var width = org[0].GetInt(); + var height = org[1].GetInt(); + var bitmap = new Bitmap(width, height); + var tiles = new List(); + PsbList data = sprImage.Children("data") as PsbList; + foreach (var tileData in data) + { + var tileDataList = tileData as PsbList; + var tile = new SprTile + { + TexId = (ushort) tileDataList[0].GetInt(), + Id = (ushort) tileDataList[1].GetInt(), + X = tileDataList[2].GetInt(), + Y = tileDataList[3].GetInt() + }; + tiles.Add(tile); + } + + using (var f = bitmap.FastLock()) + { + foreach (var tile in tiles) + { + var texId = tile.TexId; + if (!_textures.ContainsKey(texId)) + { + Logger.LogError($"Tex missing: {texId} required by: {tile}"); + continue; + } + var tex = _textures[texId]; + + var texWidth = tex.Width; + var texHeight = tex.Height; //useless, the ID is only related to width + var tilePerLine = texWidth / TileWidth; + + // 0 1 2 3 ... 31 + // ... + // 31*32 31*32+1 31*32+2 ... 31*32+31 + //calculate source rect from tile.Id + var sourceRect = new Rectangle( + (tile.Id % tilePerLine) * TileWidth, + (tile.Id / tilePerLine) * TileHeight, + TileWidth, + TileHeight + ); + var tileX = tile.X; + var tileY = tile.Y; + + f.CopyRegion(tex, sourceRect, new Rectangle(tileX * TileWidth, tileY * TileHeight, TileWidth, TileHeight)); + } + + result.Add(i.ToString(), bitmap); + } + } + + return result; + } + } +} diff --git a/FreeMote.Psb/Types/M2Types.cs b/FreeMote.Psb/Types/M2Types.cs index 85e9dec..cfe838b 100644 --- a/FreeMote.Psb/Types/M2Types.cs +++ b/FreeMote.Psb/Types/M2Types.cs @@ -13,59 +13,97 @@ class SprBlockType : BaseImageType, IPsbType public bool IsThisType(PSB psb) { - return psb.Objects.All(kv => kv.Value is PsbDictionary {Count: 3} dic && dic.ContainsKey("w") && - dic.ContainsKey("h") && - dic.ContainsKey("image")); + if (psb.Objects.All(kv => kv.Value is PsbDictionary {Count: 3} dic && dic.ContainsKey("w") && + dic.ContainsKey("h") && + dic.ContainsKey("image"))) return true; + + if (psb.Objects is PsbDictionary { Count: 3} + dic2 && dic2.ContainsKey("w") && + dic2.ContainsKey("h") && + dic2.ContainsKey("image")) + { + return true; + } + + return false; } public List CollectResources(PSB psb, bool deDuplication = true) where T : class, IResourceMetadata { var results = new List(); + if (psb.Objects is { Count: 3 } + dic && dic.ContainsKey("w") && + dic.ContainsKey("h") && + dic.ContainsKey("image")) + { + var md = GenerateMetadata("0", dic, dic["image"] as PsbResource); + results.Add(md); + } foreach (var kv in psb.Objects) { - var dic = kv.Value as PsbDictionary; - if (dic?["image"] is PsbResource res) + var d = kv.Value as PsbDictionary; + if (d?["image"] is PsbResource res) { - var name = kv.Key; - //test bit depth, for image it's 8bit (1 byte 1 pixel); for palette it's 32bit (4 byte 1 pixel) - var width = dic["w"].GetInt(); - var height = dic["h"].GetInt(); - var dataLen = res.Data.Length; - var depth = dataLen / (width * height); - PsbPixelFormat format = PsbPixelFormat.A8; - switch (depth) - { - case 1: - format = PsbPixelFormat.A8; - break; - case 4: - format = PsbPixelFormat.LeRGBA8; - break; - default: - Logger.LogWarn($"Unknown color format: {depth} bytes per pixel. Please submit sample."); - return []; - } - - ImageMetadata md = new ImageMetadata() - { - Name = name, - PsbType = PsbType, - Resource = res, - Width = width, - Height = height, - Spec = PsbSpec.none, - TypeString = format.ToStringForPsb().ToPsbString() - }; + var md = GenerateMetadata(kv.Key, d, res); results.Add(md); } } return results.Cast().ToList(); + + ImageMetadata GenerateMetadata(string name, PsbDictionary dic, PsbResource res) + { + //test bit depth, for image it's 8bit (1 byte 1 pixel); for palette it's 32bit (4 byte 1 pixel) + var width = dic["w"].GetInt(); + var height = dic["h"].GetInt(); + var dataLen = res.Data.Length; + var depth = dataLen / (width * height); + PsbPixelFormat format = PsbPixelFormat.A8; + switch (depth) + { + case 1: + format = PsbPixelFormat.A8; + break; + case 4: + format = PsbPixelFormat.LeRGBA8; + break; + default: + Logger.LogWarn($"Unknown color format: {depth} bytes per pixel. Please submit sample."); + return null; + } + + var md = new ImageMetadata() + { + Name = name, + PsbType = PsbType, + Resource = res, + Width = width, + Height = height, + Spec = PsbSpec.none, + TypeString = format.ToStringForPsb().ToPsbString() + }; + + return md; + } + } + } + + internal struct SprTile + { + public ushort TexId; + public ushort Id; + public int X; + public int Y; + + public override string ToString() + { + return $"[{TexId},{Id},{X},{Y}]"; } } //spr: data: 0: image no. 1:max to 1024 2:max to block[0]-1 3:max to block[1]-1 //block: [0] * [1] = total sprites in a tex + //spr tile: 32x32 tile class SprDataType : BaseImageType, IPsbType { public PsbType PsbType => PsbType.SprData; @@ -77,26 +115,33 @@ public bool IsThisType(PSB psb) public List CollectResources(PSB psb, bool deDuplication = true) where T : class, IResourceMetadata { - if (string.IsNullOrEmpty(psb.FilePath) || !File.Exists(psb.FilePath)) - { - //Logger.LogHint("To get images from SprData PSB, you have to put all related PSBs in a folder first."); - return []; - } - - //TODO: parse header_ex later, no sample yet. return []; } public override Dictionary OutputResources(PSB psb, FreeMountContext context, string name, string dirPath, PsbExtractOption extractOption = PsbExtractOption.Original) { - if (string.IsNullOrEmpty(psb.FilePath) || !File.Exists(psb.FilePath)) + string basePath = string.Empty; + if (context.TryGet(Consts.Context_RT_SprBasePath, out string sprBasePath)) { - Logger.LogHint("To get images from SprData PSB, you have to put all related PSBs in a folder first."); - return []; + context.Context.Remove(Consts.Context_RT_SprBasePath); + if (Directory.Exists(sprBasePath)) + { + basePath = sprBasePath; + } + } + + if (string.IsNullOrEmpty(basePath) && !string.IsNullOrEmpty(psb.FilePath)) + { + basePath = Path.GetDirectoryName(psb.FilePath); } - var basePath = Path.GetDirectoryName(psb.FilePath); + if (string.IsNullOrEmpty(basePath) || !Directory.Exists(basePath)) + { + //Logger.LogWarn("Cannot find related files. To get images from SprData PSB, you have to put all related PSBs in same folder."); + return []; + } + return []; } } diff --git a/FreeMote.Tests/PsBuildTest.cs b/FreeMote.Tests/PsBuildTest.cs index ec1df16..5f40193 100644 --- a/FreeMote.Tests/PsBuildTest.cs +++ b/FreeMote.Tests/PsBuildTest.cs @@ -9,6 +9,7 @@ using FreeMote.Plugins.Shells; using FreeMote.Psb; using FreeMote.Psb.Textures; +using FreeMote.Psb.Types; using FreeMote.PsBuild; using FreeMote.PsBuild.Converters; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -20,6 +21,8 @@ namespace FreeMote.Tests [TestClass] public class PsBuildTest { + public string ResPath = Path.Combine(Environment.CurrentDirectory, @"..\..\..\Res"); + public PsBuildTest() { } @@ -52,8 +55,7 @@ public PsBuildTest() [TestMethod] public void TestDecompile() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var paths = Directory.GetFiles(resPath, "*pure.psb"); + var paths = Directory.GetFiles(ResPath, "*pure.psb"); var target = paths[0]; var json = PsbDecompiler.Decompile(target); File.WriteAllText(target + ".json", json); @@ -62,8 +64,7 @@ public void TestDecompile() [TestMethod] public void TestDecompile2() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var psbPath = Path.Combine(resPath, "ako.pure.psb"); + var psbPath = Path.Combine(ResPath, "ako.pure.psb"); var json = PsbDecompiler.Decompile(psbPath); } @@ -71,10 +72,9 @@ public void TestDecompile2() public void TestInplaceReplace() { FreeMount.Init(); - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); //var path = Path.Combine(resPath, "dx_ふかみ_駅員服.psb"); - var path = Path.Combine(resPath, "dx_ふかみ_駅員服.lz4.psb"); - var jsonPath = Path.Combine(resPath, "dx_ふかみ_駅員服.json"); + var path = Path.Combine(ResPath, "dx_ふかみ_駅員服.lz4.psb"); + var jsonPath = Path.Combine(ResPath, "dx_ふかみ_駅員服.json"); PsbCompiler.InplaceReplaceToFile(path, jsonPath); } @@ -82,8 +82,7 @@ public void TestInplaceReplace() [TestMethod] public void TestDirectCompile() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var path = Path.Combine(resPath, "emote_test2-pure.psb"); + var path = Path.Combine(ResPath, "emote_test2-pure.psb"); PSB psb = new PSB(path); psb.Header.Version = 3; psb.UpdateIndexes(); @@ -93,8 +92,7 @@ public void TestDirectCompile() [TestMethod] public void TestJsonContext() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var path = Path.Combine(resPath, "dx_ふかみ_駅員服.resx.json"); + var path = Path.Combine(ResPath, "dx_ふかみ_駅員服.resx.json"); var obj = JsonConvert.DeserializeObject(File.ReadAllText(path)); //var flattenArrays = obj.Context[Consts.Context_FlattenArray]; //Console.WriteLine(); @@ -103,27 +101,24 @@ public void TestJsonContext() [TestMethod] public void TestCompileKrkr() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); //var path = Path.Combine(resPath, "澄怜a_裸.psb-pure.psb.json"); - var path = Path.Combine(resPath, "e-mote38_KRKR-pure.psb.json"); + var path = Path.Combine(ResPath, "e-mote38_KRKR-pure.psb.json"); PsbCompiler.CompileToFile(path, path + ".psbuild.psb", null, 4, null, PsbSpec.win); } [TestMethod] public void TestCompileWin() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); //var path = Path.Combine(resPath, "D愛子a_春服-pure.psb.json"); - var path = Path.Combine(resPath, "dx_れいなh1a1.psb.json"); + var path = Path.Combine(ResPath, "dx_れいなh1a1.psb.json"); PsbCompiler.CompileToFile(path, path + ".psbuild.psb", null, 4, null, PsbSpec.win); } [TestMethod] public void TestCompileCommon() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var path = Path.Combine(resPath, "emote396-a8l8.pure.json"); - var path2 = Path.Combine(resPath, "emote396-a8l8.pure.psb"); + var path = Path.Combine(ResPath, "emote396-a8l8.pure.json"); + var path2 = Path.Combine(ResPath, "emote396-a8l8.pure.psb"); var psb = PsbCompiler.LoadPsbFromJsonFile(path); var psb2 = new PSB(path2); //File.WriteAllBytes("396.psb", psb.Build()); @@ -133,9 +128,8 @@ public void TestCompileCommon() [TestMethod] public void TestCompileEms() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); //var path = Path.Combine(resPath, "akira_guide-pure.psb.json"); - var path = Path.Combine(resPath, "emote_test2-pure.psb.json"); + var path = Path.Combine(ResPath, "emote_test2-pure.psb.json"); var psb = PsbCompiler.LoadPsbFromJsonFile(path); psb.Platform = PsbSpec.ems; psb.Merge(); @@ -146,8 +140,7 @@ public void TestCompileEms() [TestMethod] public void TestBTree() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var path = Path.Combine(resPath, "澄怜a_裸.psb-pure.psb"); + var path = Path.Combine(ResPath, "澄怜a_裸.psb-pure.psb"); PSB psb = new PSB(path); var tree = PrefixTree.Build(psb.Names, out List oNames, out List oTrees, out List oOffsets); var list = PrefixTree.Load(oNames, oTrees, oOffsets); @@ -192,11 +185,9 @@ public void TestJsonNumbers() [TestMethod] public void TestGraft() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - //var path = Path.Combine(resPath, "澄怜a_裸.psb-pure.psb.json"); - var path = Path.Combine(resPath, "e-mote38_KRKR-pure.psb.json"); - var path2 = Path.Combine(resPath, "e-mote38_win-pure.psb.json"); + var path = Path.Combine(ResPath, "e-mote38_KRKR-pure.psb.json"); + var path2 = Path.Combine(ResPath, "e-mote38_win-pure.psb.json"); PSB psbKrkr = PsbCompiler.LoadPsbFromJsonFile(path); PSB psbWin = PsbCompiler.LoadPsbFromJsonFile(path2); psbWin.SwitchSpec(PsbSpec.krkr); @@ -231,9 +222,7 @@ public void TestGraft() [TestMethod] public void TestFindByPath() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - - var path = Path.Combine(resPath, "e-mote38_win-pure.psb.json"); + var path = Path.Combine(ResPath, "e-mote38_win-pure.psb.json"); PSB psb = PsbCompiler.LoadPsbFromJsonFile(path); var obj = psb.Objects.FindByPath("/object/all_parts/motion/タイムライン構造/bounds"); @@ -258,11 +247,9 @@ public void TestFindByPath() [TestMethod] public void TestSplitTexture() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - //var path = Path.Combine(resPath, "dx_e-mote3.0ショコラパジャマa-pure.psb.json"); //var path = Path.Combine(resPath, "ca01_l_body_1.psz.psb-pure.psb.json"); - var path = Path.Combine(resPath, "e-mote38_win-pure.psb.json"); + var path = Path.Combine(ResPath, "e-mote38_win-pure.psb.json"); //var path = Path.Combine(resPath, "akira_guide-pure.psb.json"); //PSB psb = PsbCompiler.LoadPsbFromJsonFile(path); PSB psb = new PSB("emote_krkr2win.psb"); @@ -272,9 +259,7 @@ public void TestSplitTexture() [TestMethod] public void TestPackTexture() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - - var path = Path.Combine(resPath, "澄怜a_裸.psb-pure"); + var path = Path.Combine(ResPath, "澄怜a_裸.psb-pure"); var savePath = Path.Combine(path, "packed"); Dictionary imgs = new Dictionary(); foreach (var file in Directory.EnumerateFiles(path, "*.png", SearchOption.AllDirectories)) @@ -299,9 +284,7 @@ public void TestPackTexture() [TestMethod] public void TestPathTravel() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - - var path = Path.Combine(resPath, "e-mote38_win-pure.psb.json"); + var path = Path.Combine(ResPath, "e-mote38_win-pure.psb.json"); PSB psb = PsbCompiler.LoadPsbFromJsonFile(path); var targetPath = "/object/all_parts/motion/タイムライン構造/bounds"; @@ -502,8 +485,7 @@ public void TestPsz() [TestMethod] public void TestLz4() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var path = Path.Combine(resPath, "dx_真闇_裸_lz4_linked.psb"); + var path = Path.Combine(ResPath, "dx_真闇_裸_lz4_linked.psb"); Lz4Shell shell = new Lz4Shell(); var context = new Dictionary(); var oriStream = File.OpenRead(path); @@ -516,8 +498,7 @@ public void TestLz4() [TestMethod] public void TestPsd() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var path = Path.Combine(resPath, "dx_れいなh1a1.freemote-krkr-pure.win.psb"); + var path = Path.Combine(ResPath, "dx_れいなh1a1.freemote-krkr-pure.win.psb"); PsdShell shell = new PsdShell(); var stream = File.OpenRead(path); var inShell = shell.IsInShell(stream); @@ -528,8 +509,7 @@ public void TestPsd() [TestMethod] public void TestLoadResxJson() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var path = Path.Combine(resPath, "image_info.psb.m.json"); + var path = Path.Combine(ResPath, "image_info.psb.m.json"); var resx = PsbResourceJson.LoadByPsbJsonPath(path); Console.WriteLine(resx.Context[Consts.Context_ArchiveItemFileNames]); //JObject j = (JObject)resx.Context[Consts.Context_ArchiveItemFileNames]; @@ -550,7 +530,7 @@ public void TestLoadResxJson() [TestMethod] public void TestCompareDecompile() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); + var resPath = Path.Combine(ResPath, "c01c.txt.scn"); var pccPsb = new PSB(Path.Combine(resPath, "c01c.txt.scn")); //var pccPsb = new PSB(Path.Combine(resPath, "ca01_l_body_1.psz.psb-pure.psb")); @@ -583,9 +563,8 @@ public void TestCompareDecompile() [TestMethod] public void TestGraft2() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var pathGood = Path.Combine(resPath, "goodstr.freemote.psb"); - var pathBad = Path.Combine(resPath, "goodStr.psb"); + var pathGood = Path.Combine(ResPath, "goodstr.freemote.psb"); + var pathBad = Path.Combine(ResPath, "goodStr.psb"); var psbGood = new PSB(pathGood); var psbBad = new PSB(pathBad); @@ -622,8 +601,7 @@ public void TestGraft2() [TestMethod] public void TestWin2Krkr2Win() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var pathGood = Path.Combine(resPath, "goodstr.freemote.psb"); + var pathGood = Path.Combine(ResPath, "goodstr.freemote.psb"); var psb = new PSB(pathGood); psb.SwitchSpec(PsbSpec.krkr, PsbSpec.krkr.DefaultPixelFormat()); psb.Merge(); @@ -635,9 +613,7 @@ public void TestWin2Krkr2Win() [TestMethod] public void TestTrie() { - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - //var path = Path.Combine(resPath, "e-mote38基本テンプレート(正面zバイナリ専用)_free.json"); - var path = Path.Combine(resPath, "test_kazuma.txt.scn.m.json"); + var path = Path.Combine(ResPath, "test_kazuma.txt.scn.m.json"); var psb = PsbCompiler.LoadPsbFromJsonFile(path); var names = psb.Names; var s1 = psb.ToStream().Length; @@ -652,8 +628,7 @@ public void TestTrie() public void TestExtractArchive() { FreeMount.Init(); - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var path = Path.Combine(resPath, "patch_info.psb.m"); + var path = Path.Combine(ResPath, "patch_info.psb.m"); PsbDecompiler.ExtractArchive(path, "523aad2de7132", FreeMountContext.CreateForArchive(), null, false, false, true); } @@ -662,31 +637,105 @@ public void TestPackArchive() { FreeMount.Init(); //Consts.ForceCompressionLevel = CompressionLevel.Fastest; - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var path = Path.Combine(resPath, "patch_info.psb.m.json"); + var path = Path.Combine(ResPath, "patch_info.psb.m.json"); //PsbCompiler.PackArchive(path, "523aad2de7132", true, false); PsbCompiler.PackArchive(path, "523aad2de7132", false, false); PsbDecompiler.ExtractArchive("patch_info.psb.m", "523aad2de7132", FreeMountContext.CreateForArchive(), null, false, false, true); } - + [TestMethod] public void TestSpr() { FreeMount.Init(); - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var path = Path.Combine(resPath, "Spr", "1P000.psb"); + var path = Path.Combine(ResPath, "Spr", "1PTYOURYOU.spr.psb.m.json"); - var psb = new PSB(path); - PsbDecompiler.DecompileToFile(path, extractFormat: PsbImageFormat.png, extractOption: PsbExtractOption.Extract); + var psb = PsbCompiler.LoadPsbFromJsonFile(path); + + Dictionary counter = new Dictionary(); + Dictionary> imageCounter = new(); + Dictionary> sprDic = new(); + foreach (var spr in psb.Objects["spr_data"] as PsbList) + { + PsbList p = spr.Children("data") as PsbList; + int images = spr.Children("images").GetInt(); + foreach (var inner in p) + { + PsbList inner2 = inner as PsbList; + SprTile tile = new SprTile + {TexId = (ushort) inner2[0].GetInt(), Id = (ushort) inner2[1].GetInt(), X = inner2[2].GetInt(), Y = inner2[3].GetInt()}; + if (sprDic.ContainsKey(tile.TexId)) + { + sprDic[tile.TexId].Add(tile); + } + else + { + sprDic[tile.TexId] = new List { tile }; + } + + if (imageCounter.ContainsKey(images)) + { + imageCounter[images].Add(tile); + } + else + { + imageCounter[images] = new List() {tile}; + } + + var i = inner2[0].GetInt(); + if (counter.ContainsKey(i)) + { + counter[i] += 1; + } + else + { + counter[i] = 1; + } + } + } + + //foreach (var kv in counter.OrderBy(k => k.Key)) + //{ + // Console.WriteLine($"{kv.Key}: {kv.Value}"); + //} + + //var spr1 = sprDic[1]; + //foreach (var sp in spr1) + //{ + // Console.WriteLine($"TexId: {sp.TexId}, Id: {sp.Id}, X: {sp.X}, Y: {sp.Y}"); + //} + // 99: 15L 468 ref + + var image22 = imageCounter[22]; + foreach (var sp in image22) + { + Console.WriteLine(sp); + } + } + + [TestMethod] + public void TestSprPainter() + { + var path = Path.Combine(ResPath, "Spr", "1PTYOURYOU.spr.psb.m.json"); + var psb = PsbCompiler.LoadPsbFromJsonFile(path); + var painter = new SprPainter(psb, Path.GetDirectoryName(path)); + var results = painter.Draw(); + var dir = Path.Combine(ResPath, "Spr", "1PTYOURYOU"); + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + foreach (var kv in results) + { + kv.Value.Save(Path.Combine(dir, $"{kv.Key}.png")); + } } [TestMethod] public void TestClut() { FreeMount.Init(); - var resPath = Path.Combine(Environment.CurrentDirectory, @"..\..\Res"); - var path = Path.Combine(resPath, "Spr", "image.psb.m"); + var path = Path.Combine(ResPath, "Spr", "image.psb.m"); var psb = new PSB(path); PsbDecompiler.DecompileToFile(path, extractFormat: PsbImageFormat.png, extractOption: PsbExtractOption.Extract); diff --git a/FreeMote/Consts.cs b/FreeMote/Consts.cs index b6d0bab..480af88 100644 --- a/FreeMote/Consts.cs +++ b/FreeMote/Consts.cs @@ -119,6 +119,11 @@ public static class Consts /// public const string Context_BodyBinName = "BodyBinName"; + /// + /// (string?) Base path to find Sprites for SprData type + /// + public const string Context_RT_SprBasePath = "[RT]SprBasePath"; + /// /// 0x075BCD15 ///