1
0
mirror of synced 2024-11-30 18:24:39 +01:00

A few fixes

Fix the UV editor not applying saved UV data.
Start to add basic LM2 dict file support.
Start to add GFA support (todo need BPE compression)
This commit is contained in:
KillzXGaming 2019-07-02 16:12:23 -04:00
parent f12a85a83a
commit c30f758f8d
23 changed files with 881 additions and 149 deletions

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Switch_Toolbox;
using System.Windows.Forms;
using Switch_Toolbox.Library;
using Switch_Toolbox.Library.IO;
namespace FirstPlugin
{
public class GFA : IArchiveFile, IFileFormat
{
public FileType FileType { get; set; } = FileType.Archive;
public bool CanSave { get; set; }
public string[] Description { get; set; } = new string[] { "Good Feel Archive" };
public string[] Extension { get; set; } = new string[] { "*.gfa" };
public string FileName { get; set; }
public string FilePath { get; set; }
public IFileInfo IFileInfo { get; set; }
public bool CanAddFiles { get; set; }
public bool CanRenameFiles { get; set; }
public bool CanReplaceFiles { get; set; } = true;
public bool CanDeleteFiles { get; set; }
public bool Identify(System.IO.Stream stream)
{
using (var reader = new Switch_Toolbox.Library.IO.FileReader(stream, true))
{
return reader.CheckSignature(4, "GFAC");
}
}
public Type[] Types
{
get
{
List<Type> types = new List<Type>();
return types.ToArray();
}
}
public List<FileEntry> files = new List<FileEntry>();
public IEnumerable<ArchiveFileInfo> Files => files;
private uint Unknown1;
private uint Version;
public void Load(System.IO.Stream stream)
{
using (var reader = new FileReader(stream))
{
reader.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
reader.ReadSignature(4, "GFAC");
Unknown1 = reader.ReadUInt32();
Version = reader.ReadUInt32();
uint FileInfoOffset = reader.ReadUInt32();
uint FileInfoSize = reader.ReadUInt32();
uint DataOffset = reader.ReadUInt32();
uint DataSize = reader.ReadUInt32();
byte[] Padding = reader.ReadBytes(0x10); //Not sure
reader.SeekBegin(FileInfoOffset);
uint FileCount = reader.ReadUInt32();
for (int i = 0; i < FileCount; i++)
{
var file = new FileEntry();
file.Read(reader);
files.Add(file);
}
reader.SeekBegin(DataOffset);
reader.ReadSignature(4, "GFCP");
uint VersionGFCP = reader.ReadUInt32();
uint CompressionType = reader.ReadUInt32();
uint DecompressedSize = reader.ReadUInt32();
uint CompressedSize = reader.ReadUInt32();
}
}
public void Unload()
{
}
public byte[] Save()
{
var mem = new System.IO.MemoryStream();
using (var writer = new FileWriter(mem))
{
writer.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
writer.WriteSignature("GFAC");
writer.Write(Unknown1);
writer.Write(Version);
writer.Write(uint.MaxValue); //Info offset for later
writer.Write(uint.MaxValue); //Info size for later
writer.Write(uint.MaxValue); //Data offset for later
writer.Write(uint.MaxValue); //Data size for later
writer.Write(new byte[0x10]); //Padding
writer.WriteUint32Offset(12); //Save info offset
writer.Write(files.Count);
/* //Save info
for (int i = 0; i < files.Count; i++)
files[i].Write(writer);
//Save strings and offsets
for (int i = 0; i < files.Count; i++)
files[i].Write(writer);
writer.Write(new uint[files.Count]); //Save space for offsets
for (int i = 0; i < files.Count; i++)
writer.Write(files[i].FileData.Length);
*/
}
return mem.ToArray();
}
private void Align(FileWriter writer, int alignment)
{
var startPos = writer.Position;
long position = writer.Seek((-writer.Position % alignment + alignment) % alignment, System.IO.SeekOrigin.Current);
writer.Seek(startPos, System.IO.SeekOrigin.Begin);
while (writer.Position != position)
{
writer.Write((byte)0x30);
}
}
public bool AddFile(ArchiveFileInfo archiveFileInfo)
{
return false;
}
public bool DeleteFile(ArchiveFileInfo archiveFileInfo)
{
return false;
}
public class FileEntry : ArchiveFileInfo
{
public uint Hash { get; set; }
public void Read(FileReader reader)
{
Hash = reader.ReadUInt32();
FileName = GetName(reader);
uint Size = reader.ReadUInt32();
uint Offset = reader.ReadUInt32();
}
}
private static string GetName(FileReader reader)
{
uint Offset = reader.ReadUInt32();
using (reader.TemporarySeek(Offset & 0x00ffffff, System.IO.SeekOrigin.Begin))
{
return reader.ReadZeroTerminatedString();
}
}
}
}

View File

@ -0,0 +1,324 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Switch_Toolbox;
using System.Windows.Forms;
using Switch_Toolbox.Library;
using Switch_Toolbox.Library.IO;
using Switch_Toolbox.Library.Forms;
using System.Drawing;
namespace FirstPlugin
{
//Parse info based on https://github.com/TheFearsomeDzeraora/LM2L
public class LM2_DICT : TreeNodeFile, IFileFormat
{
public FileType FileType { get; set; } = FileType.Archive;
public bool CanSave { get; set; }
public string[] Description { get; set; } = new string[] { "Luigi's Mansion 2 Dark Moon Archive Dictionary" };
public string[] Extension { get; set; } = new string[] { "*.dict" };
public string FileName { get; set; }
public string FilePath { get; set; }
public IFileInfo IFileInfo { get; set; }
public bool CanAddFiles { get; set; }
public bool CanRenameFiles { get; set; }
public bool CanReplaceFiles { get; set; }
public bool CanDeleteFiles { get; set; }
public bool Identify(System.IO.Stream stream)
{
using (var reader = new Switch_Toolbox.Library.IO.FileReader(stream, true))
{
reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;
return reader.ReadUInt32() == 0x5824F3A9;
}
}
public Type[] Types
{
get
{
List<Type> types = new List<Type>();
return types.ToArray();
}
}
public List<FileEntry> files = new List<FileEntry>();
public bool IsCompressed = false;
public void Load(System.IO.Stream stream)
{
using (var reader = new FileReader(stream))
{
reader.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
uint Identifier = reader.ReadUInt32();
ushort Unknown = reader.ReadUInt16(); //Could also be 2 bytes, not sure. Always 0x0401
IsCompressed = reader.ReadByte() == 1;
reader.ReadByte(); //Padding
uint FileCount = reader.ReadUInt32();
uint LargestCompressedFile = reader.ReadUInt32();
reader.SeekBegin(0x2C);
byte[] Unknowns = reader.ReadBytes((int)FileCount);
for (int i = 0; i < FileCount; i++)
{
var file = new FileEntry(this);
file.Read(reader);
if (file.FileType != 0)
{
file.Text = $"File {i} (Unknowns {file.FileType} {file.Unknown2} {file.Unknown3})";
files.Add(file);
}
}
//Now go through each file and format and connect the headers and blocks
uint ImageIndex = 0;
List<TexturePOWE> Textures = new List<TexturePOWE>();
TreeNode textureFolder = new TreeNode("Textures");
Nodes.Add(textureFolder);
for (int i = 0; i < files.Count; i++)
{
if (files[i].FileType == FileEntry.FileDataType.Texture)
{
if (files[i].Unknown3 == 1) //Info
{
//Read the info
using (var textureReader = new FileReader(files[i].FileData))
{
while (textureReader.ReadUInt32() == TexturePOWE.Identifier)
{
var texture = new TexturePOWE();
texture.Index = ImageIndex;
texture.Read(textureReader);
texture.Text = $"Texture {ImageIndex}";
textureFolder.Nodes.Add(texture);
Textures.Add(texture);
}
}
}
else //Block
{
foreach (var tex in Textures)
{
if (tex.Index == ImageIndex)
tex.ImageData = files[i].FileData;
}
ImageIndex++;
}
}
else
Nodes.Add(files[i]);
}
}
}
public void Unload()
{
}
public byte[] Save()
{
return null;
}
public bool AddFile(ArchiveFileInfo archiveFileInfo)
{
return false;
}
public bool DeleteFile(ArchiveFileInfo archiveFileInfo)
{
return false;
}
public class TexturePOWE : STGenericTexture
{
public static readonly uint Identifier = 0xE977D350;
public uint Index { get; set; }
public uint ID { get; set; }
public uint ImageSize { get; set; }
public uint ID2 { get; set; }
public byte[] ImageData { get; set; }
public void Read(FileReader reader)
{
PlatformSwizzle = PlatformSwizzle.Platform_3DS;
ID = reader.ReadUInt32();
ImageSize = reader.ReadUInt32();
ID2 = reader.ReadUInt32();
reader.Seek(0x8);
Width = reader.ReadUInt16();
Height = reader.ReadUInt16();
reader.Seek(3);
var numMips = reader.ReadByte();
reader.Seek(0x14);
byte FormatCtr = reader.ReadByte();
reader.Seek(3);
MipCount = 1;
Format = CTR_3DS.ConvertPICAToGenericFormat((CTR_3DS.PICASurfaceFormat)FormatCtr);
}
public override void OnClick(TreeView treeview)
{
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.Instance.GetActiveContent(typeof(ImageEditorBase));
if (editor == null)
{
editor = new ImageEditorBase();
editor.Dock = DockStyle.Fill;
LibraryGUI.Instance.LoadEditor(editor);
}
editor.Text = Text;
editor.LoadProperties(this.GenericProperties);
editor.LoadImage(this);
}
public override bool CanEdit { get; set; } = false;
public override void SetImageData(Bitmap bitmap, int ArrayLevel)
{
throw new NotImplementedException();
}
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0)
{
return ImageData;
}
public override TEX_FORMAT[] SupportedFormats
{
get
{
return new TEX_FORMAT[]
{
TEX_FORMAT.B5G6R5_UNORM,
TEX_FORMAT.R8G8_UNORM,
TEX_FORMAT.B5G5R5A1_UNORM,
TEX_FORMAT.B4G4R4A4_UNORM,
TEX_FORMAT.LA8,
TEX_FORMAT.HIL08,
TEX_FORMAT.L8,
TEX_FORMAT.A8_UNORM,
TEX_FORMAT.LA4,
TEX_FORMAT.A4,
TEX_FORMAT.ETC1_UNORM,
TEX_FORMAT.ETC1_A4,
};
}
}
}
public class FileEntry : TreeNodeCustom
{
public LM2_DICT ParentDictionary { get; set; }
public uint Offset;
public uint DecompressedSize;
public uint CompressedSize;
public FileDataType FileType;
public byte Unknown2;
public byte Unknown3; //Possibly the effect? 0 for image block, 1 for info
public enum FileDataType : ushort
{
Texture = 0x80,
}
public byte[] FileData
{
get { return GetData(); }
set
{
}
}
public override void OnClick(TreeView treeview)
{
HexEditor editor = (HexEditor)LibraryGUI.Instance.GetActiveContent(typeof(HexEditor));
if (editor == null)
{
editor = new HexEditor();
LibraryGUI.Instance.LoadEditor(editor);
}
editor.Dock = DockStyle.Fill;
editor.LoadData(FileData);
}
public FileEntry(LM2_DICT dict)
{
ParentDictionary = dict;
}
public void Read(FileReader reader)
{
Offset = reader.ReadUInt32();
DecompressedSize = reader.ReadUInt32();
CompressedSize = reader.ReadUInt32();
FileType = reader.ReadEnum<FileDataType>(false);
Unknown2 = reader.ReadByte();
Unknown3 = reader.ReadByte();
}
private bool IsTextureBinary()
{
byte[] Data = GetData();
if (Data.Length < 4)
return false;
using (var reader = new FileReader(Data))
{
return reader.ReadUInt32() == 0xE977D350;
}
}
private byte[] GetData()
{
byte[] Data = new byte[DecompressedSize];
string FolderPath = System.IO.Path.GetDirectoryName(ParentDictionary.FilePath);
string DataFile = System.IO.Path.Combine(FolderPath, $"{ParentDictionary.FileName.Replace(".dict", ".data")}");
if (System.IO.File.Exists(DataFile))
{
using (var reader = new FileReader(DataFile))
{
reader.SeekBegin(Offset);
if (ParentDictionary.IsCompressed)
{
ushort Magic = reader.ReadUInt16();
reader.SeekBegin(Offset);
Data = reader.ReadBytes((int)CompressedSize);
if (Magic == 0x9C78 || Magic == 0xDA78)
return STLibraryCompression.ZLIB.Decompress(Data);
else //Unknown compression
return Data;
}
else
{
return reader.ReadBytes((int)DecompressedSize);
}
}
}
return Data;
}
}
}
}

View File

@ -94,8 +94,10 @@ namespace FirstPlugin
public void Read(FileReader reader)
{
char[] name = reader.ReadChars(128);
FileName = new string(name);
long pos = reader.Position;
FileName = reader.ReadZeroTerminatedString();
reader.SeekBegin(pos + 128);
uint Offset = reader.ReadUInt32();
CompressedSize = reader.ReadUInt32();
uint Unknown = reader.ReadUInt32();
@ -104,8 +106,9 @@ namespace FirstPlugin
using (reader.TemporarySeek((int)Offset, System.IO.SeekOrigin.Begin))
{
FileData = reader.ReadBytes((int)CompressedSize);
// STLibraryCompression.LZSS.Decompress(FileData, DecompressedSize);
reader.ReadBytes(8);
FileData = reader.ReadBytes((int)CompressedSize - 8);
FileData = STLibraryCompression.LZSS.Decompress(FileData, DecompressedSize);
}
}
}

View File

@ -109,6 +109,7 @@ namespace FirstPlugin
public byte[] DecompressBlock()
{
byte[] data = GetBlock();
Console.WriteLine("DATA " + data.Length);
var reader = new FileReader(data);
reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;
@ -121,7 +122,8 @@ namespace FirstPlugin
uint decompSize = reader.ReadUInt32();
uint compSize = (uint)reader.BaseStream.Length - 8;
return STLibraryCompression.MTA_CUSTOM.Decompress(data, decompSize);
var comp = new STLibraryCompression.MTA_CUSTOM();
return comp.Decompress(data, decompSize);
}
else if (compType == 0x30)
{

View File

@ -1328,6 +1328,12 @@ namespace Bfres.Structs
output.Z = input.X * matrix.M13 + input.Y * matrix.M23 + input.Z * matrix.M33 + matrix.M43;
return output;
}
public override void SaveVertexBuffer()
{
SaveVertexBuffer(GetResFileU() != null);
}
public void SaveVertexBuffer(bool IsWiiU)
{
if (IsWiiU)

View File

@ -335,8 +335,8 @@ namespace FirstPlugin
Formats.Add(typeof(NCA));
Formats.Add(typeof(RARC));
Formats.Add(typeof(ME01));
// Formats.Add(typeof(LM2_DICT));
//Formats.Add(typeof(GFA));
//Unfinished wip formats not ready for use
if (Runtime.DEVELOPER_DEBUG_MODE)

View File

@ -198,7 +198,9 @@
<Compile Include="FileFormats\AAMP\AAMP.cs" />
<Compile Include="FileFormats\Archives\APAK.cs" />
<Compile Include="FileFormats\Archives\ARC.cs" />
<Compile Include="FileFormats\Archives\GFA.cs" />
<Compile Include="FileFormats\Archives\IGA_PAK.cs" />
<Compile Include="FileFormats\Archives\LM2\LM2_DICT.cs" />
<Compile Include="FileFormats\Archives\LZARC.cs" />
<Compile Include="FileFormats\Archives\ME01.cs" />
<Compile Include="FileFormats\Archives\MKGPDX_PAC.cs" />
@ -280,7 +282,7 @@
<Compile Include="GL\Helpers\AlphaGLControl.cs" />
<Compile Include="GL\Helpers\ColorGLControl.cs" />
<Compile Include="GUI\AAMP\AampEditor.cs">
<SubType>Form</SubType>
<SubType>UserControl</SubType>
</Compile>
<Compile Include="GUI\AAMP\AampEditor.Designer.cs">
<DependentUpon>AampEditor.cs</DependentUpon>
@ -469,7 +471,7 @@
<Compile Include="GUI\Byaml\CourseMuunt\Wrappers\ProbeLightingEntryWrapper.cs" />
<Compile Include="GUI\Byaml\CourseMuunt\Wrappers\ProbeLightingWrapper.cs" />
<Compile Include="GUI\Editors\EffectTableEditor.cs">
<SubType>Form</SubType>
<SubType>UserControl</SubType>
</Compile>
<Compile Include="GUI\Editors\EffectTableEditor.Designer.cs">
<DependentUpon>EffectTableEditor.cs</DependentUpon>
@ -481,7 +483,7 @@
<DependentUpon>CollisionMaterialEditor.cs</DependentUpon>
</Compile>
<Compile Include="GUI\Message\MSBTEditor.cs">
<SubType>Form</SubType>
<SubType>UserControl</SubType>
</Compile>
<Compile Include="GUI\Message\MSBTEditor.Designer.cs">
<DependentUpon>MSBTEditor.cs</DependentUpon>
@ -498,10 +500,10 @@
</Compile>
<Compile Include="GUI\SMO\MarioCostumeEditor.cs" />
<Compile Include="GUI\AAMP\AampV1Editor.cs">
<SubType>Form</SubType>
<SubType>UserControl</SubType>
</Compile>
<Compile Include="GUI\AAMP\AampV2Editor.cs">
<SubType>Form</SubType>
<SubType>UserControl</SubType>
</Compile>
<Compile Include="GUI\AAMP\EditBox.cs">
<SubType>Form</SubType>
@ -776,7 +778,7 @@
<DependentUpon>AttributeEditor.cs</DependentUpon>
</Compile>
<Compile Include="GUI\Editors\MK8TrackEditor\MK8MapCameraEditor.cs">
<SubType>Form</SubType>
<SubType>UserControl</SubType>
</Compile>
<Compile Include="GUI\Editors\MK8TrackEditor\MK8MapCameraEditor.Designer.cs">
<DependentUpon>MK8MapCameraEditor.cs</DependentUpon>
@ -857,7 +859,7 @@
<SubType>Form</SubType>
</Compile>
<Compile Include="GUI\Byaml\ByamlEditor.cs">
<SubType>Form</SubType>
<SubType>UserControl</SubType>
</Compile>
<Compile Include="GUI\Byaml\ByamlEditor.Designer.cs">
<DependentUpon>ByamlEditor.cs</DependentUpon>

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Runtime.InteropServices;
using Switch_Toolbox.Library.IO;
namespace Switch_Toolbox.Library
{
public class LZ77_WII
{
public static byte[] Decompress(byte[] input)
{
if (input == null) throw new ArgumentNullException(nameof(input));
return input;
}
}
}

View File

@ -65,7 +65,7 @@ namespace Switch_Toolbox.Library.IO
{
if (br.ReadString(4) == "ZCMP")
{
return DecompressZCMP(b);
return DecompressZCMP(b);
}
else
{
@ -119,16 +119,33 @@ namespace Switch_Toolbox.Library.IO
}
}
public class BPE
{
public static unsafe byte[] Decompress(byte[] input, uint decompressedLength)
{
fixed (byte* outputPtr = new byte[decompressedLength])
{
fixed (byte* inputPtr = input)
{
Decompress(outputPtr, inputPtr, decompressedLength);
}
byte[] decomp = new byte[decompressedLength];
Marshal.Copy((IntPtr)outputPtr, decomp, 0, decomp.Length);
return decomp;
}
}
public static unsafe void Decompress(byte* output, byte* input, uint decompressedLength)
{
}
}
//Mario Tennis Aces Custom compression
public class MTA_CUSTOM
{
private static uint Swap(uint X)
{
return ((X >> 24) & 0xff | (X >> 8) & 0xff00 |
(X << 8) & 0xff0000 | (X << 24) & 0xff000000);
}
public static unsafe byte[] Decompress(byte[] input, uint decompressedLength)
public unsafe byte[] Decompress(byte[] input, uint decompressedLength)
{
fixed (byte* outputPtr = new byte[decompressedLength])
{
@ -145,7 +162,7 @@ namespace Switch_Toolbox.Library.IO
//Thanks Simon. Code ported from
//https://github.com/simontime/MarioTennisAces0x50Decompressor/blob/master/decompress.c
public static unsafe void Decompress(byte* output, byte* input, uint decompressedLength)
public unsafe void Decompress(byte* output, byte* input, uint decompressedLength)
{
uint pos = 8;
byte* end = input + decompressedLength;
@ -158,8 +175,6 @@ namespace Switch_Toolbox.Library.IO
{
uint flag;
Console.WriteLine($"Pass 1 ");
while (true)
{
flag = 0xFF000000 * data[0];
@ -171,28 +186,36 @@ namespace Switch_Toolbox.Library.IO
for (int i = 0; i < 8; i++)
*output++ = *data++;
CheckFinished(data, end);
var checkFinished = CheckFinished(data, end);
data = checkFinished.data;
end = checkFinished.end;
}
Console.WriteLine($"Pass 2 ");
flag |= 0x800000;
data++;
Console.WriteLine($"flag " + flag);
//IterateFlag
while ((flag & 0x80000000) == 0)
{
IterateFlag(flag, data, output);
flag <<= 1;
*output++ = *data++;
}
Console.WriteLine($"Pass 3 ");
while (true)
{
flag <<= 1;
if (flag == 0)
CheckFinished(data, end);
{
var checkFinished2 = CheckFinished(data, end);
data = checkFinished2.data;
end = checkFinished2.end;
}
int op_ofs = (data[0] >> 4) | (data[1] << 4);
int op_len = data[0] & 0xF;
@ -200,7 +223,7 @@ namespace Switch_Toolbox.Library.IO
if (op_ofs == 0)
return;
byte* chunk = output -op_ofs;
byte* chunk = output - op_ofs;
if (op_len > 1)
data += 2;
else
@ -215,7 +238,14 @@ namespace Switch_Toolbox.Library.IO
op_len = op_len_ext + add_len;
if (op_ofs >= 2)
Loop1(flag, op_len, chunk, data, output);
{
var loop1Data = Loop1(flag, op_len, chunk, data, output);
flag = loop1Data.flag;
op_len = loop1Data.op_len;
chunk = loop1Data.chunk;
data = loop1Data.data;
output = loop1Data.output;
}
}
else
{
@ -223,165 +253,232 @@ namespace Switch_Toolbox.Library.IO
op_len = op_len_ext;
if (op_ofs >= 2)
{
Loop1(flag, op_len, chunk, data, output);
Loop2(flag, op_len, data, output, chunk);
var loop1Data = Loop1(flag, op_len, chunk, data, output);
flag = loop1Data.flag;
op_len = loop1Data.op_len;
chunk = loop1Data.chunk;
data = loop1Data.data;
output = loop1Data.output;
}
}
}
var loop2Data2 = Loop2(flag, op_len, data, output, chunk);
flag = loop2Data2.flag;
op_len = loop2Data2.op_len;
chunk = loop2Data2.chunk;
data = loop2Data2.data;
output = loop2Data2.output;
}
}
EndOperation(data, end);
var endOp = EndOperation(data, end);
data = endOp.data;
end = endOp.end;
}
}
private static unsafe void Loop1(uint flag, int op_len, byte* chunk, byte* data, byte* output)
{
if (((*chunk ^ *output) & 1) == 0)
{
if ((*chunk & 1) != 0)
private unsafe class Data
{
public uint flag;
public int op_len;
public byte* chunk;
public byte* data;
public byte* output;
public byte* end;
}
unsafe Data Loop1(uint flag, int op_len, byte* chunk, byte* data, byte* output)
{
if ((((byte)*chunk ^ (byte)*output) & 1) == 0)
{
*output++ = *chunk++;
op_len--;
}
int op_len_sub = op_len - 2;
if (op_len >= 2)
{
int masked_len = ((op_len_sub >> 1) + 1) & 7;
byte* out_ptr = output;
byte* chunk_ptr = chunk;
if (masked_len != 0)
if (((byte)*chunk & 1) != 0)
{
while (masked_len-- != 0)
{
*out_ptr++ = *chunk_ptr++;
*out_ptr++ = *chunk_ptr++;
op_len -= 2;
}
*output++ = *chunk++;
op_len--;
}
uint masked_ext_len = (uint)op_len_sub & 0xFFFFFFFE;
uint op_len_sub = (uint)op_len - 2;
if (op_len_sub >= 0xE)
if (op_len >= 2)
{
do
int masked_len = (((int)op_len_sub >> 1) + 1) & 7;
byte* out_ptr = output;
byte* chunk_ptr = chunk;
if (masked_len != 0)
{
for (int i = 0; i < 0x10; i++)
while (masked_len-- != 0)
{
*out_ptr++ = *chunk_ptr++;
op_len -= 0x10;
*out_ptr++ = *chunk_ptr++;
op_len -= 2;
}
}
while (op_len > 1);
uint masked_ext_len = op_len_sub & 0xFFFFFFFE;
if (op_len_sub >= 0xE)
{
do
{
for (int i = 0; i < 0x10; i++)
*out_ptr++ = *chunk_ptr++;
op_len -= 0x10;
}
while (op_len > 1);
}
output += masked_ext_len + 2;
op_len = (int)op_len_sub - (int)masked_ext_len;
chunk += masked_ext_len + 2;
}
output += masked_ext_len + 2;
op_len = op_len_sub - (int)masked_ext_len;
chunk += masked_ext_len + 2;
if (op_len == 0)
{
if ((flag & 0x80000000) == 0)
{
flag <<= 1;
*output++ = *data++;
}
}
}
if (op_len == 0)
CheckFlag(flag, data, output);
return Loop2(flag, op_len, data, output, chunk);
}
Loop2(flag, op_len, data, output, chunk);
}
private static unsafe void Loop2(uint flag, int op_len, byte* data, byte* output, byte* chunk)
{
int masked_len = op_len & 7;
byte* out_ptr = output;
byte* chunk_ptr = chunk;
if (masked_len != 0)
unsafe Data Loop2(uint flag, int op_len, byte* data, byte* output, byte* chunk)
{
while (masked_len-- != 0)
*out_ptr++ = *chunk_ptr++;
}
int masked_len = op_len & 7;
byte* out_ptr = output;
byte* chunk_ptr = chunk;
if (op_len - 1 >= 7)
{
do
if (masked_len != 0)
{
for (int i = 0; i < 8; i++)
while (masked_len-- != 0)
*out_ptr++ = *chunk_ptr++;
}
while (chunk_ptr != chunk + op_len);
if (op_len - 1 >= 7)
{
do
{
for (int i = 0; i < 8; i++)
*out_ptr++ = *chunk_ptr++;
}
while (chunk_ptr != chunk + op_len);
}
output += op_len;
if ((flag & 0x80000000) == 0)
{
flag <<= 1;
*output++ = *data++;
}
return new Data()
{
flag = flag,
op_len = op_len,
data = data,
output = output,
chunk = chunk,
};
}
output += op_len;
unsafe Data CheckFinished(byte* data, byte* end)
{
if (data >= end)
return EndOperation(data, end);
CheckFlag(flag, data, output);
}
return new Data()
{
data = data,
end = end,
};
}
private static unsafe void CheckFlag(uint flag, byte* data, byte* output)
{
if ((flag & 0x80000000) == 0)
IterateFlag(flag, data, output);
}
unsafe Data EndOperation(byte* data, byte* end)
{
byte* ext = end + 0x20;
if (data < ext)
do
*end-- = *--ext;
while (data < ext);
private static unsafe void IterateFlag(uint flag, byte* data, byte* output)
{
flag <<= 1;
*output++ = *data++;
}
private static unsafe void CheckFinished(byte* data, byte* end)
{
if (data >= end)
EndOperation(data, end);
}
private static unsafe void EndOperation(byte* data, byte* end)
{
byte* ext = end + 0x20;
if (data < ext)
do
*end-- = *--ext;
while (data < ext);
return new Data()
{
data = data,
end = end,
};
}
}
public class LZSS
{
//From https://github.com/IcySon55/Kuriimu/blob/f670c2719affc1eaef8b4c40e40985881247acc7/src/Kontract/Compression/LZSS.cs
//Todo does not work with Paper Mario Color Splash
public static byte[] Decompress(byte[] data, uint decompressedLength)
static class LzssParameters
{
using (FileReader reader = new FileReader(new MemoryStream(data), true))
/// <summary>Size of the ring buffer.</summary>
public const int N = 4096;
/// <summary>Maximum match length for position coding. (0x0F + THRESHOLD).</summary>
public const int F = 18;
/// <summary>Minimum match length for position coding.</summary>
public const int THRESHOLD = 3;
/// <summary>Index for root of binary search trees.</summary>
public const int NIL = N;
/// <summary>Character used to fill the ring buffer initially.</summary>
//private const ubyte BUFF_INIT = ' ';
public const byte BUFF_INIT = 0; // Changed for F-Zero GX
}
public static byte[] Decompress(byte[] input, uint decompressedLength)
{
List<byte> output = new List<byte>();
byte[] ringBuf = new byte[LzssParameters.N];
int inputPos = 0, ringBufPos = LzssParameters.N - LzssParameters.F;
ushort flags = 0;
// Clear ringBuf with a character that will appear often
for (int i = 0; i < LzssParameters.N - LzssParameters.F; i++)
ringBuf[i] = LzssParameters.BUFF_INIT;
while (inputPos < input.Length)
{
List<byte> result = new List<byte>();
// Use 16 bits cleverly to count to 8.
// (After 8 shifts, the high bits will be cleared).
if ((flags & 0xFF00) == 0)
flags = (ushort)(input[inputPos++] | 0x8000);
for (int i = 0, flags = 0; ; i++)
if ((flags & 1) == 1)
{
if (i % 8 == 0) flags = reader.ReadByte();
if ((flags & 0x80) == 0) result.Add(reader.ReadByte());
else
{
int lengthDist = BitConverter.ToUInt16(reader.ReadBytes(2).Reverse().ToArray(), 0);
int offs = lengthDist % 4096 + 1;
int length = lengthDist / 4096 + 3;
while (length > 0)
{
result.Add(result[result.Count - offs]);
length--;
}
}
if (result.Count == decompressedLength)
{
return result.ToArray();
}
else if (result.Count > decompressedLength)
{
throw new InvalidDataException("Went past the end of the stream");
}
flags <<= 1;
// Copy data literally from input
byte c = input[inputPos++];
output.Add(c);
ringBuf[ringBufPos++ % LzssParameters.N] = c;
}
else
{
// Copy data from the ring buffer (previous data).
int index = ((input[inputPos + 1] & 0xF0) << 4) | input[inputPos];
int count = (input[inputPos + 1] & 0x0F) + LzssParameters.THRESHOLD;
inputPos += 2;
for (int i = 0; i < count; i++)
{
byte c = ringBuf[(index + i) % LzssParameters.N];
output.Add(c);
ringBuf[ringBufPos++ % LzssParameters.N] = c;
}
}
// Advance flags & count bits
flags >>= 1;
}
return output.ToArray();
}
}

View File

@ -437,6 +437,7 @@ namespace Switch_Toolbox.Library.Forms
shape.TransformUVs(Translate, Scale, UvChannelIndex);
shape.UpdateVertexData();
shape.SaveVertexBuffer();
}
scaleXUD.Value = 1;

View File

@ -24,6 +24,11 @@ namespace Switch_Toolbox.Library
}
public virtual void SaveVertexBuffer()
{
}
public List<STGenericPolygonGroup> PolygonGroups = new List<STGenericPolygonGroup>();
public bool HasPos;

View File

@ -144,7 +144,7 @@ namespace Switch_Toolbox.Library
set {
if (value == 0)
mipCount = 1;
else if (value > 14)
else if (value > 17)
throw new Exception($"Invalid mip map count! Texture: {Text} Value: {value}");
else
mipCount = value;

View File

@ -189,6 +189,16 @@ namespace Switch_Toolbox.Library.IO
return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true,
CompressionType.Yaz0, DecompressedFileSize, CompressedFileSize);
}
if (Path.GetExtension(FileName) == ".lz")
{
if (data == null)
data = File.ReadAllBytes(FileName);
data = LZ77_WII.Decompress(fileReader.getSection(16, data.Length - 16));
return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true,
CompressionType.Yaz0, DecompressedFileSize, CompressedFileSize);
}
if (MagicHex == 0x28B52FFD || MagicHex == 0xFD2FB528)
{
if (data != null)

View File

@ -210,6 +210,7 @@
<Compile Include="Audio\VGAudioFile.cs" />
<Compile Include="Collections\SortExtensions.cs" />
<Compile Include="Compression\LZ4F.cs" />
<Compile Include="Compression\LZ77_WII.cs" />
<Compile Include="Compression\STLibraryCompression.cs" />
<Compile Include="Compression\ZCMP.cs" />
<Compile Include="Config.cs" />

View File

@ -657,6 +657,100 @@ namespace Switch_Toolbox.Library.Old
return ((X - 1) | (Y - 1)) + 1;
}
public static byte[] Decode(GX2Surface tex, int ArrayIndex = -1, int MipIndex = -1, string DebugTextureName = "")
{
uint blkWidth, blkHeight;
if (IsFormatBCN((GX2SurfaceFormat)tex.format))
{
blkWidth = 4;
blkHeight = 4;
}
else
{
blkWidth = 1;
blkHeight = 1;
}
var surfInfo = getSurfaceInfo((GX2SurfaceFormat)tex.format, tex.width, tex.height, tex.depth, (uint)tex.dim, (uint)tex.tileMode, (uint)tex.aa, 0);
uint bpp = DIV_ROUND_UP(surfInfo.bpp, 8);
if (tex.numArray == 0)
tex.numArray = 1;
byte[] data = new byte[tex.data.Length];
byte[] mipdata = new byte[0];
if (tex.mipData != null)
mipdata = new byte[tex.mipData.Length];
uint mipCount = tex.numMips;
if (tex.mipData == null || tex.mipData.Length <= 0)
mipCount = 1;
int dataOffset = 0;
int mipDataOffset = 0;
int mipSpliceSize = 0;
for (int arrayLevel = 0; arrayLevel < tex.depth; arrayLevel++)
{
for (int mipLevel = 0; mipLevel < mipCount; mipLevel++)
{
bool GetLevel = (arrayLevel == ArrayIndex && mipLevel == MipIndex);
uint swizzle = tex.swizzle;
uint width_ = (uint)Math.Max(1, tex.width >> mipLevel);
uint height_ = (uint)Math.Max(1, tex.height >> mipLevel);
uint size = DIV_ROUND_UP(width_, blkWidth) * DIV_ROUND_UP(height_, blkHeight) * bpp;
uint mipOffset;
if (mipLevel != 0)
{
if (tex.mip_swizzle != 0)
swizzle = tex.mip_swizzle;
mipOffset = (tex.mipOffset[mipLevel - 1]);
if (mipLevel == 1)
{
mipOffset -= (uint)surfInfo.surfSize;
mipOffset += (uint)mipDataOffset;
mipSpliceSize += (int)mipOffset;
}
Console.WriteLine("mipOffset " + mipOffset);
if (GetLevel)
{
surfInfo = getSurfaceInfo((GX2SurfaceFormat)tex.format, tex.width, tex.height, tex.depth, (uint)tex.dim, (uint)tex.tileMode, (uint)tex.aa, mipLevel);
Array.Copy(tex.mipData, 0, mipdata, 0, tex.mipData.Length);
Array.Copy(tex.mipData, (int)mipOffset, mipdata, 0, (int)surfInfo.sliceSize);
data = mipdata;
}
}
else if (GetLevel)
{
Array.Copy(tex.data, 0, data, 0, tex.data.Length);
Array.Copy(tex.data, (uint)dataOffset, data, 0, size);
}
if (GetLevel)
{
byte[] deswizzled = deswizzle(width_, height_, surfInfo.depth, surfInfo.height, (uint)tex.format,
surfInfo.tileMode, (uint)swizzle, surfInfo.pitch, surfInfo.bpp, data, arrayLevel);
//Create a copy and use that to remove uneeded data
byte[] result_ = new byte[size];
Array.Copy(deswizzled, 0, result_, 0, size);
return result_;
}
}
dataOffset += (int)surfInfo.sliceSize;
mipDataOffset += mipSpliceSize;
}
return null;
}
public static List<List<byte[]>> Decode(GX2Surface tex, string DebugTextureName = "")
{
if (tex.data == null || tex.data.Length <= 0)