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:
parent
f12a85a83a
commit
c30f758f8d
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
169
Switch_FileFormatsMain/FileFormats/Archives/GFA.cs
Normal file
169
Switch_FileFormatsMain/FileFormats/Archives/GFA.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
324
Switch_FileFormatsMain/FileFormats/Archives/LM2/LM2_DICT.cs
Normal file
324
Switch_FileFormatsMain/FileFormats/Archives/LM2/LM2_DICT.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
Binary file not shown.
Binary file not shown.
18
Switch_Toolbox_Library/Compression/LZ77_WII.cs
Normal file
18
Switch_Toolbox_Library/Compression/LZ77_WII.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -437,6 +437,7 @@ namespace Switch_Toolbox.Library.Forms
|
||||
|
||||
shape.TransformUVs(Translate, Scale, UvChannelIndex);
|
||||
shape.UpdateVertexData();
|
||||
shape.SaveVertexBuffer();
|
||||
}
|
||||
|
||||
scaleXUD.Value = 1;
|
||||
|
@ -24,6 +24,11 @@ namespace Switch_Toolbox.Library
|
||||
|
||||
}
|
||||
|
||||
public virtual void SaveVertexBuffer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public List<STGenericPolygonGroup> PolygonGroups = new List<STGenericPolygonGroup>();
|
||||
|
||||
public bool HasPos;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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" />
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user