Fix LM2 textures with multiple image blocks
This commit is contained in:
parent
3e40842844
commit
d25d10c22b
Binary file not shown.
@ -82,14 +82,9 @@ namespace FirstPlugin
|
||||
List<TexturePOWE> Textures = new List<TexturePOWE>();
|
||||
|
||||
TreeNode textureFolder = new TreeNode("Textures");
|
||||
Nodes.Add(textureFolder);
|
||||
|
||||
for (int i = 0; i < files.Count; i++)
|
||||
{
|
||||
Nodes.Add(files[i]);
|
||||
|
||||
continue;
|
||||
|
||||
if (files[i].FileType == FileEntry.FileDataType.Texture)
|
||||
{
|
||||
if (files[i].Unknown3 == 1) //Info
|
||||
@ -100,6 +95,8 @@ namespace FirstPlugin
|
||||
while (textureReader.ReadUInt32() == TexturePOWE.Identifier)
|
||||
{
|
||||
var texture = new TexturePOWE();
|
||||
texture.ImageKey = "texture";
|
||||
texture.SelectedImageKey = texture.ImageKey;
|
||||
texture.Index = ImageIndex;
|
||||
texture.Read(textureReader);
|
||||
texture.Text = $"Texture {ImageIndex}";
|
||||
@ -110,10 +107,15 @@ namespace FirstPlugin
|
||||
}
|
||||
else //Block
|
||||
{
|
||||
uint Offset = 0;
|
||||
foreach (var tex in Textures)
|
||||
{
|
||||
if (tex.Index == ImageIndex)
|
||||
tex.ImageData = files[i].FileData;
|
||||
{
|
||||
tex.ImageData = Utils.SubArray(files[i].FileData, Offset, tex.ImageSize);
|
||||
}
|
||||
|
||||
Offset += tex.ImageSize;
|
||||
}
|
||||
ImageIndex++;
|
||||
}
|
||||
@ -121,6 +123,9 @@ namespace FirstPlugin
|
||||
else
|
||||
Nodes.Add(files[i]);
|
||||
}
|
||||
|
||||
if (textureFolder.Nodes.Count > 0)
|
||||
Nodes.Add(textureFolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Toolbox;
|
||||
using System.Windows.Forms;
|
||||
using Toolbox.Library;
|
||||
using Toolbox.Library.IO;
|
||||
using Toolbox.Library.Forms;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
public class GameDataToc : TreeNodeFile, IFileFormat
|
||||
{
|
||||
public FileType FileType { get; set; } = FileType.Archive;
|
||||
|
||||
public bool CanSave { get; set; }
|
||||
public string[] Description { get; set; } = new string[] { "GameDataToc" };
|
||||
public string[] Extension { get; set; } = new string[] { "*.toc" };
|
||||
public string FileName { get; set; }
|
||||
public string FilePath { get; set; }
|
||||
public IFileInfo IFileInfo { get; set; }
|
||||
|
||||
public bool Identify(System.IO.Stream stream)
|
||||
{
|
||||
using (var reader = new Toolbox.Library.IO.FileReader(stream, true))
|
||||
{
|
||||
return FileName == "GameData.toc";
|
||||
}
|
||||
}
|
||||
|
||||
public Type[] Types
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>();
|
||||
return types.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public string EncryptionKey = "b0110b704a259cd8f0da9e4480bd0b9c8c7c94c609f322288273cf85930dd64f7baf13255b075df912e81c2d8aae98fe034dee5f61c232c4b39280fe4c68c46151be7f49b7cbd4ee0922acb02aaa76bc9585dfb89c5fb90da7094289ea18c81312839b06fd267273c81babea38405276a1d35835916e7cec88f26473abb79578762e3abe0ce719309114aa40dcf8d7466e4edc1b8a887d1ed7fad0c7d418fe81660ea5b9445d2db47174cc1bfaa2c96eb84cca8e447c95ef12a76e745c7d19497d4729beaba244eb992f2e46934920caa5ad09d6950e0f9fefdac6104b5609379eff0ad4de56a941e63baf25924dcdcb5632d27b58108d5af19ea2b3946986514940bd4953396391450286ac8f47e07b95a8ab59a770ac71acbf51ba9c8f4c18fb88865f1d49577fd14da819223d4c78a49f888d78141bfa140669eda3d890e05f6d85b8058042b127e50feb1a6fdf28a309309646ff3081933d93293239de9c74c55f0589b3658bb2764833a1001ec8c6dcba7c610d15df27fd7938da58ea7c877c0fd38c267ca295b50e37560c702b1a8f0fa9227eccbbc2b0d6e704b8a1bd65a3fb42250557c8675b1f9ebd6ce056fbf0098ee03e3ba75fc29dbc9217de62b67a04f82abb8b8b2eca5ee0ee89219805281b56c0beb6db5269c45cf330cbd7e1a7579456e380e7027ef77b4fb6fd2d9df00248357e72b206ed8d6db3577a7cf81c04dbf054ffbe69b2cede6ca266172a138754b588b48ff686c728838c4c9c4342045fd74e68f28b7d0f86a5bfbee86d5122b838aeab59cddf8acc7d71416f2239d2a22db3ee83cd0396089dbae3bf9f7bf7081ec8591c159507d0a1d2b8d34f477c45dfa2341716be64ab445bef8494fb8f2aa9b5dd60d1e61a22e5b44f73dfcabf407ba0e35f1a95d69cd73e42a3e9d966bf439c3b69fb82df4929a8d65fa734dcf39c738053bb17f3296b270b3a859970083b9eb0b9732f87f96502c443327902b14827056b3711c5518d8b2ef250f4a958d61fa89ade5c2af1759a57a2403dad07c1611bfd99736ac5c86b9079b676401ea10e6dd5fbf3078e1ae6723b63f4d3908c0b9b7f679b3b25ae7e7b98ba9c127936ba9a0e86466edb580681e4f92f1b8b0c91d2ca57a65c98f03f69c8946fd93c5051cf5210aa5e7d9a13e58c464170cc6d770e3078dfde6602c7c6526f216cbb6b28db3c8a442546092342531b875c887d66f57722e7b850161483c18ac2ab6cea7fb67f05f5636a2776c0dee80913a8cec042f9d48e4db79365cf0c36f6c6446328311134b1677218549f65bcd2e7ace3a303250a66cb942dfd4d234d20ef14315ad5c460a460fa26f56efe98448b72ab374e7fc6de475b801fa3ba1f0562370894e0815f545a6c671a5b0d89fc9ec983e26aea00e1b1407e4d278de74b31d5aaae78a5edbc439011ceb2db";
|
||||
|
||||
public byte[] DecryptedTable { get; set; }
|
||||
|
||||
public static byte[] EncryptOrDecryptXor(byte[] text, byte[] key)
|
||||
{
|
||||
byte[] xor = new byte[text.Length];
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
xor[i] = (byte)(text[i] ^ key[i % key.Length]);
|
||||
}
|
||||
return xor;
|
||||
}
|
||||
|
||||
private byte[] FromHex(string hex)
|
||||
{
|
||||
byte[] raw = new byte[hex.Length / 2];
|
||||
for (int i = 0; i < raw.Length; i++)
|
||||
{
|
||||
raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
//Decryption process from https://github.com/TheFearsomeDzeraora/BFTTFutil/blob/master/Program.cs
|
||||
public void Load(System.IO.Stream stream)
|
||||
{
|
||||
Text = FileName;
|
||||
|
||||
using (var reader = new FileReader(stream))
|
||||
{
|
||||
byte[] table = reader.ReadBytes((int)reader.BaseStream.Length);
|
||||
DecryptedTable = FromHex(EncryptionKey);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] StringToByteArray(string hex)
|
||||
{
|
||||
|
||||
|
||||
return Enumerable.Range(0, hex.Length)
|
||||
.Where(x => x % 2 == 0)
|
||||
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public override void OnClick(TreeView treeview)
|
||||
{
|
||||
HexEditor editor = (HexEditor)LibraryGUI.GetActiveContent(typeof(HexEditor));
|
||||
if (editor == null)
|
||||
{
|
||||
editor = new HexEditor();
|
||||
LibraryGUI.LoadEditor(editor);
|
||||
}
|
||||
editor.Text = Text;
|
||||
editor.Dock = DockStyle.Fill;
|
||||
editor.LoadData(DecryptedTable);
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
|
||||
}
|
||||
public byte[] Save()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -105,11 +105,11 @@ namespace FirstPlugin
|
||||
case ChunkAnimInfo:
|
||||
if (chunk.ChunkSize > 0xB0)
|
||||
{
|
||||
// reader.Seek(chunk.Position + 0xB0, System.IO.SeekOrigin.Begin);
|
||||
// chunk.FileName = reader.ReadString(Syroot.BinaryData.BinaryStringFormat.ZeroTerminated);
|
||||
reader.Seek(chunk.Position + 0xB0, System.IO.SeekOrigin.Begin);
|
||||
chunk.FileName = reader.ReadString(Syroot.BinaryData.BinaryStringFormat.ZeroTerminated);
|
||||
}
|
||||
break;
|
||||
/* case ChunkAnimData:
|
||||
case ChunkAnimData:
|
||||
AnimationFile animFile = new AnimationFile();
|
||||
animFile.Read(reader);
|
||||
chunk.ChunkData = animFile;
|
||||
@ -128,7 +128,7 @@ namespace FirstPlugin
|
||||
MaterialFile matFile = new MaterialFile();
|
||||
matFile.Read(reader);
|
||||
chunk.ChunkData = matFile;
|
||||
break;*/
|
||||
break;
|
||||
}
|
||||
|
||||
reader.Seek(chunk.Position + chunk.ChunkSize, System.IO.SeekOrigin.Begin);
|
||||
@ -182,47 +182,47 @@ namespace FirstPlugin
|
||||
|
||||
public void ReadChunk(FileReader reader)
|
||||
{
|
||||
reader.SetByteOrder(true);
|
||||
reader.SetByteOrder(true);
|
||||
|
||||
Console.WriteLine("TEX pos " + reader.Position);
|
||||
GX2Surface = new GX2.GX2Surface();
|
||||
GX2Surface.dim = reader.ReadUInt32();
|
||||
GX2Surface.width = reader.ReadUInt32();
|
||||
GX2Surface.height = reader.ReadUInt32();
|
||||
GX2Surface.depth = reader.ReadUInt32();
|
||||
GX2Surface.numMips = reader.ReadUInt32();
|
||||
GX2Surface.format = reader.ReadUInt32();
|
||||
GX2Surface.aa = reader.ReadUInt32();
|
||||
GX2Surface.use = reader.ReadUInt32();
|
||||
GX2Surface.imageSize = reader.ReadUInt32();
|
||||
GX2Surface.imagePtr = reader.ReadUInt32();
|
||||
GX2Surface.mipSize = reader.ReadUInt32();
|
||||
GX2Surface.mipPtr = reader.ReadUInt32();
|
||||
GX2Surface.tileMode = reader.ReadUInt32();
|
||||
GX2Surface.swizzle = reader.ReadUInt32();
|
||||
GX2Surface.alignment = reader.ReadUInt32();
|
||||
GX2Surface.pitch = reader.ReadUInt32();
|
||||
GX2Surface.mipOffset = reader.ReadUInt32s(13);
|
||||
GX2Surface.firstMip = reader.ReadUInt32();
|
||||
GX2Surface.imageCount = reader.ReadUInt32();
|
||||
GX2Surface.firstSlice = reader.ReadUInt32();
|
||||
GX2Surface.numSlices = reader.ReadUInt32();
|
||||
GX2Surface.compSel = reader.ReadBytes(4);
|
||||
GX2Surface.texRegs = reader.ReadUInt32s(4);
|
||||
Console.WriteLine("TEX pos " + reader.Position);
|
||||
GX2Surface = new GX2.GX2Surface();
|
||||
GX2Surface.dim = reader.ReadUInt32();
|
||||
GX2Surface.width = reader.ReadUInt32();
|
||||
GX2Surface.height = reader.ReadUInt32();
|
||||
GX2Surface.depth = reader.ReadUInt32();
|
||||
GX2Surface.numMips = reader.ReadUInt32();
|
||||
GX2Surface.format = reader.ReadUInt32();
|
||||
GX2Surface.aa = reader.ReadUInt32();
|
||||
GX2Surface.use = reader.ReadUInt32();
|
||||
GX2Surface.imageSize = reader.ReadUInt32();
|
||||
GX2Surface.imagePtr = reader.ReadUInt32();
|
||||
GX2Surface.mipSize = reader.ReadUInt32();
|
||||
GX2Surface.mipPtr = reader.ReadUInt32();
|
||||
GX2Surface.tileMode = reader.ReadUInt32();
|
||||
GX2Surface.swizzle = reader.ReadUInt32();
|
||||
GX2Surface.alignment = reader.ReadUInt32();
|
||||
GX2Surface.pitch = reader.ReadUInt32();
|
||||
GX2Surface.mipOffset = reader.ReadUInt32s(13);
|
||||
GX2Surface.firstMip = reader.ReadUInt32();
|
||||
GX2Surface.imageCount = reader.ReadUInt32();
|
||||
GX2Surface.firstSlice = reader.ReadUInt32();
|
||||
GX2Surface.numSlices = reader.ReadUInt32();
|
||||
GX2Surface.compSel = reader.ReadBytes(4);
|
||||
GX2Surface.texRegs = reader.ReadUInt32s(4);
|
||||
|
||||
RedChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[0]);
|
||||
GreenChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[1]);
|
||||
BlueChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[2]);
|
||||
AlphaChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[3]);
|
||||
RedChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[0]);
|
||||
GreenChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[1]);
|
||||
BlueChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[2]);
|
||||
AlphaChannel = GX2ChanneToGeneric((Syroot.NintenTools.Bfres.GX2.GX2CompSel)GX2Surface.compSel[3]);
|
||||
|
||||
if (GX2Surface.numMips > 13)
|
||||
return;
|
||||
if (GX2Surface.numMips > 13)
|
||||
return;
|
||||
|
||||
Width = GX2Surface.width;
|
||||
Height = GX2Surface.height;
|
||||
MipCount = GX2Surface.numMips;
|
||||
ArrayCount = GX2Surface.numArray;
|
||||
Format = Bfres.Structs.FTEX.ConvertFromGx2Format((Syroot.NintenTools.Bfres.GX2.GX2SurfaceFormat)GX2Surface.format);
|
||||
Width = GX2Surface.width;
|
||||
Height = GX2Surface.height;
|
||||
MipCount = GX2Surface.numMips;
|
||||
ArrayCount = GX2Surface.numArray;
|
||||
Format = Bfres.Structs.FTEX.ConvertFromGx2Format((Syroot.NintenTools.Bfres.GX2.GX2SurfaceFormat)GX2Surface.format);
|
||||
}
|
||||
|
||||
private STChannelType GX2ChanneToGeneric(Syroot.NintenTools.Bfres.GX2.GX2CompSel comp)
|
@ -211,9 +211,10 @@
|
||||
<Compile Include="FileFormats\Archives\NXARC.cs" />
|
||||
<Compile Include="FileFormats\Archives\RARC.cs" />
|
||||
<Compile Include="FileFormats\Archives\SARC_OLD.cs" />
|
||||
<Compile Include="FileFormats\Archives\SPC.cs" />
|
||||
<Compile Include="FileFormats\Archives\SWU.cs" />
|
||||
<Compile Include="FileFormats\Archives\SP2.cs" />
|
||||
<Compile Include="FileFormats\Archives\Sonic Racing\GameDataToc.cs" />
|
||||
<Compile Include="FileFormats\Archives\Sonic Racing\SPC.cs" />
|
||||
<Compile Include="FileFormats\Archives\Sonic Racing\SWU.cs" />
|
||||
<Compile Include="FileFormats\Archives\Sonic Racing\SP2.cs" />
|
||||
<Compile Include="FileFormats\Archives\TMPK.cs" />
|
||||
<Compile Include="FileFormats\Archives\U8.cs" />
|
||||
<Compile Include="FileFormats\Audio\Archives\BARS.cs" />
|
||||
|
@ -332,6 +332,7 @@ namespace FirstPlugin
|
||||
Formats.Add(typeof(SP2));
|
||||
Formats.Add(typeof(SWU));
|
||||
Formats.Add(typeof(SPC));
|
||||
Formats.Add(typeof(GameDataToc));
|
||||
Formats.Add(typeof(NUSHDB));
|
||||
Formats.Add(typeof(MKGPDX_PAC));
|
||||
Formats.Add(typeof(LZARC));
|
||||
|
@ -35,6 +35,9 @@ namespace Toolbox.Library
|
||||
}
|
||||
public class ArchiveFileInfo : INode
|
||||
{
|
||||
[Browsable(false)]
|
||||
public string SourceFile { get; internal set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public string ImageKey { get; set; }
|
||||
|
||||
@ -433,6 +436,9 @@ namespace Toolbox.Library
|
||||
if (!node.CanLoadFile)
|
||||
continue;
|
||||
|
||||
if (!((IFileFormat)archiveFile).IFileInfo.InArchive && File.Exists(((IFileFormat)archiveFile).FilePath))
|
||||
node.SourceFile = ((IFileFormat)archiveFile).FilePath;
|
||||
|
||||
string nodeString = node.FileName;
|
||||
|
||||
var roots = nodeString.Split(new char[] { '/' },
|
||||
|
Loading…
Reference in New Issue
Block a user