mirror of
https://github.com/KillzXGaming/Switch-Toolbox
synced 2024-11-26 06:20:24 +00:00
Add TPL rebuilding and add support for TPL mipmaps.
This commit is contained in:
parent
cc81f88c9a
commit
c47ce7d60f
4 changed files with 616 additions and 422 deletions
|
@ -1,421 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Toolbox;
|
||||
using System.Windows.Forms;
|
||||
using Toolbox.Library;
|
||||
using Toolbox.Library.Forms;
|
||||
using Toolbox.Library.IO;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
public class TPL : TreeNodeFile, IFileFormat, ITextureContainer
|
||||
{
|
||||
public FileType FileType { get; set; } = FileType.Image;
|
||||
|
||||
public bool CanSave { get; set; }
|
||||
public string[] Description { get; set; } = new string[] { "TPL" };
|
||||
public string[] Extension { get; set; } = new string[] { "*.tpl" };
|
||||
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 FileReader(stream, true))
|
||||
{
|
||||
reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;
|
||||
return reader.ReadUInt32() == 0x0020AF30 || Utils.GetExtension(FileName) == ".tpl";
|
||||
}
|
||||
}
|
||||
|
||||
public Type[] Types
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>();
|
||||
return types.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public bool DisplayIcons => true;
|
||||
|
||||
public List<STGenericTexture> TextureList
|
||||
{
|
||||
get
|
||||
{
|
||||
List<STGenericTexture> textures = new List<STGenericTexture>();
|
||||
foreach (STGenericTexture node in Nodes)
|
||||
textures.Add(node);
|
||||
|
||||
return textures;
|
||||
}
|
||||
set { }
|
||||
}
|
||||
|
||||
public List<ImageHeader> ImageHeaders = new List<ImageHeader>();
|
||||
public List<PaletteHeader> PaletteHeaders = new List<PaletteHeader>();
|
||||
|
||||
public override void OnAfterAdded()
|
||||
{
|
||||
if (Nodes.Count > 0 && this.TreeView != null)
|
||||
this.TreeView.SelectedNode = Nodes[0];
|
||||
}
|
||||
|
||||
public void Load(System.IO.Stream stream)
|
||||
{
|
||||
Text = FileName;
|
||||
|
||||
using (var reader = new FileReader(stream))
|
||||
{
|
||||
reader.SetByteOrder(true);
|
||||
|
||||
uint Identifier = reader.ReadUInt32();
|
||||
|
||||
//TPL has multiple versions i assume? Some games like F Zero use a custom one so try that
|
||||
if (Identifier != 0x0020AF30)
|
||||
{
|
||||
reader.Position = 0;
|
||||
uint ImageCount = reader.ReadUInt32();
|
||||
for (int i = 0; i < ImageCount; i++)
|
||||
{
|
||||
reader.SeekBegin(4 + (i * 0x10));
|
||||
|
||||
var image = new ImageHeader();
|
||||
|
||||
image.Format = (Decode_Gamecube.TextureFormats)reader.ReadUInt32();
|
||||
image.ImageOffset = reader.ReadUInt32();
|
||||
image.Width = reader.ReadUInt16();
|
||||
image.Height = reader.ReadUInt16();
|
||||
image.MaxLOD = (byte)reader.ReadUInt16();
|
||||
ushort unknown = reader.ReadUInt16();
|
||||
|
||||
if ((uint)image.Format == 256)
|
||||
break;
|
||||
|
||||
Console.WriteLine(image.ImageOffset);
|
||||
Console.WriteLine(image.Format);
|
||||
|
||||
//Now create a wrapper
|
||||
var texWrapper = new TplTextureWrapper(this, image);
|
||||
string name = System.IO.Path.GetFileNameWithoutExtension(FileName);
|
||||
if (ImageCount == 1)
|
||||
texWrapper.Text = name;
|
||||
else
|
||||
texWrapper.Text = $"{name}_{i}";
|
||||
texWrapper.ImageKey = "Texture";
|
||||
texWrapper.SelectedImageKey = "Texture";
|
||||
texWrapper.Format = Decode_Gamecube.ToGenericFormat(image.Format);
|
||||
texWrapper.Width = image.Width;
|
||||
texWrapper.Height = image.Height;
|
||||
texWrapper.MipCount = image.MaxLOD;
|
||||
texWrapper.ImageData = reader.getSection(image.ImageOffset, (uint)Decode_Gamecube.GetDataSize(image.Format, (int)image.Width, (int)image.Height));
|
||||
texWrapper.PlatformSwizzle = PlatformSwizzle.Platform_Gamecube;
|
||||
Nodes.Add(texWrapper);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint ImageCount = reader.ReadUInt32();
|
||||
uint ImageOffsetTable = reader.ReadUInt32();
|
||||
|
||||
for (int i = 0; i < ImageCount; i++)
|
||||
{
|
||||
reader.SeekBegin(ImageOffsetTable + (i * 8));
|
||||
|
||||
uint ImageHeaderOffset = reader.ReadUInt32();
|
||||
uint PaletteHeaderOffset = reader.ReadUInt32();
|
||||
|
||||
reader.SeekBegin(ImageHeaderOffset);
|
||||
var image = new ImageHeader();
|
||||
image.Read(reader);
|
||||
ImageHeaders.Add(image);
|
||||
|
||||
Console.WriteLine($"ImageOffset {image.ImageOffset}");
|
||||
|
||||
//Now create a wrapper
|
||||
var texWrapper = new TplTextureWrapper(this, image);
|
||||
string name = System.IO.Path.GetFileNameWithoutExtension(FileName);
|
||||
if (ImageCount == 1)
|
||||
texWrapper.Text = name;
|
||||
else
|
||||
texWrapper.Text = $"{name}_{i}";
|
||||
|
||||
texWrapper.ImageKey = "Texture";
|
||||
texWrapper.SelectedImageKey = "Texture";
|
||||
texWrapper.Format = Decode_Gamecube.ToGenericFormat(image.Format);
|
||||
texWrapper.Width = image.Width;
|
||||
texWrapper.Height = image.Height;
|
||||
texWrapper.MipCount = 1;
|
||||
texWrapper.PlatformSwizzle = PlatformSwizzle.Platform_Gamecube;
|
||||
texWrapper.ImageData = reader.getSection(image.ImageOffset,
|
||||
(uint)Decode_Gamecube.GetDataSize(image.Format, (int)image.Width, (int)image.Height));
|
||||
|
||||
Console.WriteLine($"PaletteHeaderOffset {PaletteHeaderOffset}");
|
||||
Console.WriteLine($"ImageData { texWrapper.ImageData.Length}");
|
||||
|
||||
//Palette is sometimes unused to check
|
||||
if (PaletteHeaderOffset != 0)
|
||||
{
|
||||
reader.SeekBegin(PaletteHeaderOffset);
|
||||
var palette = new PaletteHeader();
|
||||
palette.Read(reader);
|
||||
PaletteHeaders.Add(palette);
|
||||
|
||||
var GXPaletteFormat = (Decode_Gamecube.PaletteFormats)palette.PaletteFormat;
|
||||
image.PaletteFormat = GXPaletteFormat;
|
||||
|
||||
Console.WriteLine($"GXPaletteFormat {GXPaletteFormat}");
|
||||
texWrapper.SetPaletteData(palette.Data, Decode_Gamecube.ToGenericPaletteFormat(GXPaletteFormat));
|
||||
}
|
||||
|
||||
Nodes.Add(texWrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TplTextureWrapper : STGenericTexture
|
||||
{
|
||||
public TPL TPLParent { get; set; }
|
||||
|
||||
public byte[] ImageData { get; set; }
|
||||
public ImageHeader ImageHeader;
|
||||
|
||||
public TplTextureWrapper(TPL tpl, ImageHeader header) {
|
||||
TPLParent = tpl;
|
||||
ImageHeader = header;
|
||||
|
||||
CanReplace = true;
|
||||
}
|
||||
|
||||
public override TEX_FORMAT[] SupportedFormats
|
||||
{
|
||||
get
|
||||
{
|
||||
return new TEX_FORMAT[]
|
||||
{
|
||||
TEX_FORMAT.I4,
|
||||
TEX_FORMAT.I8,
|
||||
TEX_FORMAT.IA4,
|
||||
TEX_FORMAT.IA8,
|
||||
TEX_FORMAT.RGB565,
|
||||
TEX_FORMAT.RGB5A3,
|
||||
TEX_FORMAT.RGBA32,
|
||||
TEX_FORMAT.C4,
|
||||
TEX_FORMAT.C8,
|
||||
TEX_FORMAT.C14X2,
|
||||
TEX_FORMAT.CMPR,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override bool CanEdit { get; set; } = false;
|
||||
|
||||
public override void SetImageData(System.Drawing.Bitmap bitmap, int ArrayLevel)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0, int DepthLevel = 0)
|
||||
{
|
||||
return Decode_Gamecube.GetMipLevel(ImageData, Width, Height, MipCount, (uint)MipLevel, Format);
|
||||
}
|
||||
|
||||
public override void OnClick(TreeView treeView)
|
||||
{
|
||||
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase));
|
||||
if (editor == null)
|
||||
{
|
||||
editor = new ImageEditorBase();
|
||||
editor.Dock = DockStyle.Fill;
|
||||
LibraryGUI.LoadEditor(editor);
|
||||
}
|
||||
|
||||
editor.LoadProperties(ImageHeader);
|
||||
editor.LoadImage(this);
|
||||
}
|
||||
|
||||
public void UpdateEditor()
|
||||
{
|
||||
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase));
|
||||
if (editor == null)
|
||||
{
|
||||
editor = new ImageEditorBase();
|
||||
editor.Dock = DockStyle.Fill;
|
||||
LibraryGUI.LoadEditor(editor);
|
||||
}
|
||||
|
||||
editor.LoadProperties(GenericProperties);
|
||||
editor.LoadImage(this);
|
||||
}
|
||||
|
||||
public override void Replace(string FileName)
|
||||
{
|
||||
GamecubeTextureImporterList importer = new GamecubeTextureImporterList(SupportedFormats);
|
||||
GameCubeTextureImporterSettings settings = new GameCubeTextureImporterSettings();
|
||||
|
||||
importer.ForceMipCount = true;
|
||||
importer.SelectedMipCount = 1;
|
||||
|
||||
if (Utils.GetExtension(FileName) == ".dds" ||
|
||||
Utils.GetExtension(FileName) == ".dds2")
|
||||
{
|
||||
settings.LoadDDS(FileName);
|
||||
importer.LoadSettings(new List<GameCubeTextureImporterSettings>() { settings, });
|
||||
|
||||
ApplySettings(settings);
|
||||
UpdateEditor();
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.LoadBitMap(FileName);
|
||||
importer.LoadSettings(new List<GameCubeTextureImporterSettings>() { settings, });
|
||||
|
||||
if (importer.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
if (settings.GenerateMipmaps && !settings.IsFinishedCompressing)
|
||||
settings.Compress();
|
||||
|
||||
ApplySettings(settings);
|
||||
UpdateEditor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplySettings(GameCubeTextureImporterSettings settings)
|
||||
{
|
||||
this.ImageData = settings.DataBlockOutput[0];
|
||||
this.Width = settings.TexWidth;
|
||||
this.Height = settings.TexHeight;
|
||||
this.Format = settings.GenericFormat;
|
||||
this.MipCount = 1; //Always 1
|
||||
this.Depth = 1;
|
||||
this.ArrayCount = (uint)settings.DataBlockOutput.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public class PaletteHeader
|
||||
{
|
||||
public ushort EntryCount { get; set; }
|
||||
public byte Unpacked { get; set; }
|
||||
public uint PaletteFormat { get; set; }
|
||||
public uint PaletteDataOffset { get; set; }
|
||||
|
||||
public byte[] Data;
|
||||
|
||||
public void Read(FileReader reader)
|
||||
{
|
||||
EntryCount = reader.ReadUInt16();
|
||||
Unpacked = reader.ReadByte();
|
||||
reader.ReadByte();
|
||||
PaletteFormat = reader.ReadUInt32();
|
||||
PaletteDataOffset = reader.ReadUInt32();
|
||||
|
||||
using (reader.TemporarySeek(PaletteDataOffset, SeekOrigin.Begin))
|
||||
{
|
||||
Data = reader.ReadBytes(EntryCount * 2);
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(FileWriter writer)
|
||||
{
|
||||
writer.Write(EntryCount);
|
||||
writer.Write(Unpacked);
|
||||
writer.Write((byte)0);
|
||||
writer.Write(PaletteFormat);
|
||||
writer.Write(PaletteDataOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageHeader
|
||||
{
|
||||
[ReadOnly(true)]
|
||||
public Decode_Gamecube.TextureFormats Format { get; set; }
|
||||
[ReadOnly(true)]
|
||||
public Decode_Gamecube.PaletteFormats PaletteFormat { get; set; }
|
||||
|
||||
[ReadOnly(true)]
|
||||
public ushort Width { get; set; }
|
||||
[ReadOnly(true)]
|
||||
public ushort Height { get; set; }
|
||||
[Browsable(false)]
|
||||
public uint ImageOffset { get; set; }
|
||||
|
||||
public float LODBias { get; set; }
|
||||
public bool EdgeLODEnable { get; set; }
|
||||
|
||||
public WrapMode WrapS { get; set; }
|
||||
public WrapMode WrapT { get; set; }
|
||||
public FilterMode MinFilter { get; set; }
|
||||
public FilterMode MagFilter { get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public byte MinLOD { get; set; }
|
||||
[Browsable(false)]
|
||||
public byte MaxLOD { get; set; }
|
||||
[Browsable(false)]
|
||||
public byte Unpacked { get; set; }
|
||||
|
||||
public void Read(FileReader reader)
|
||||
{
|
||||
Height = reader.ReadUInt16();
|
||||
Width = reader.ReadUInt16();
|
||||
Format = (Decode_Gamecube.TextureFormats)reader.ReadUInt32();
|
||||
ImageOffset = reader.ReadUInt32();
|
||||
WrapS = (WrapMode)reader.ReadUInt32();
|
||||
WrapT = (WrapMode)reader.ReadUInt32();
|
||||
MinFilter = (FilterMode)reader.ReadUInt32();
|
||||
MagFilter = (FilterMode)reader.ReadUInt32();
|
||||
LODBias = reader.ReadSingle();
|
||||
EdgeLODEnable = reader.ReadBoolean();
|
||||
MinLOD = reader.ReadByte();
|
||||
MaxLOD = reader.ReadByte();
|
||||
Unpacked = reader.ReadByte();
|
||||
}
|
||||
|
||||
public void Write(FileWriter writer)
|
||||
{
|
||||
writer.Write(Width);
|
||||
writer.Write(Height);
|
||||
writer.Write((uint)Format);
|
||||
writer.Write(ImageOffset);
|
||||
writer.Write((uint)WrapS);
|
||||
writer.Write((uint)WrapT);
|
||||
writer.Write((uint)MinFilter);
|
||||
writer.Write((uint)MagFilter);
|
||||
writer.Write(LODBias);
|
||||
writer.Write(EdgeLODEnable);
|
||||
writer.Write(MinLOD);
|
||||
writer.Write(MaxLOD);
|
||||
writer.Write(Unpacked);
|
||||
}
|
||||
}
|
||||
|
||||
public enum WrapMode : uint
|
||||
{
|
||||
Clamp,
|
||||
Repeat,
|
||||
Mirror
|
||||
}
|
||||
|
||||
public enum FilterMode : uint
|
||||
{
|
||||
Nearest,
|
||||
Linear,
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Save(System.IO.Stream stream)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
315
File_Format_Library/FileFormats/Texture/TPL/TPL.cs
Normal file
315
File_Format_Library/FileFormats/Texture/TPL/TPL.cs
Normal file
|
@ -0,0 +1,315 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Toolbox;
|
||||
using System.Windows.Forms;
|
||||
using Toolbox.Library;
|
||||
using Toolbox.Library.Forms;
|
||||
using Toolbox.Library.IO;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
public class TPL : TreeNodeFile, IFileFormat, ITextureContainer
|
||||
{
|
||||
public FileType FileType { get; set; } = FileType.Image;
|
||||
|
||||
public bool CanSave { get; set; }
|
||||
public string[] Description { get; set; } = new string[] { "TPL" };
|
||||
public string[] Extension { get; set; } = new string[] { "*.tpl" };
|
||||
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 FileReader(stream, true))
|
||||
{
|
||||
reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;
|
||||
return reader.ReadUInt32() == 0x0020AF30 || Utils.GetExtension(FileName) == ".tpl";
|
||||
}
|
||||
}
|
||||
|
||||
public Type[] Types
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>();
|
||||
return types.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public bool DisplayIcons => true;
|
||||
|
||||
public List<STGenericTexture> TextureList
|
||||
{
|
||||
get
|
||||
{
|
||||
List<STGenericTexture> textures = new List<STGenericTexture>();
|
||||
foreach (STGenericTexture node in Nodes)
|
||||
textures.Add(node);
|
||||
|
||||
return textures;
|
||||
}
|
||||
set { }
|
||||
}
|
||||
|
||||
|
||||
public override void OnAfterAdded()
|
||||
{
|
||||
if (Nodes.Count > 0 && this.TreeView != null)
|
||||
this.TreeView.SelectedNode = Nodes[0];
|
||||
}
|
||||
|
||||
public static TPL CreateNewFromImage()
|
||||
{
|
||||
OpenFileDialog ofd = new OpenFileDialog();
|
||||
ofd.Multiselect = false;
|
||||
ofd.Filter = FileFilters.REV_TEX;
|
||||
if (ofd.ShowDialog() != DialogResult.OK)
|
||||
return null;
|
||||
|
||||
TPL tpl = new TPL();
|
||||
tpl.IFileInfo = new IFileInfo();
|
||||
tpl.FileName = Path.GetFileNameWithoutExtension(ofd.FileName) + ".tpl";
|
||||
tpl.Header = new TPL_IO.Header();
|
||||
var image = TplTextureWrapper.Create(tpl, tpl.Header, ofd.FileName);
|
||||
if (image == null) //Operation cancelled
|
||||
return null;
|
||||
|
||||
tpl.Nodes.Add(image);
|
||||
return tpl;
|
||||
}
|
||||
|
||||
private TPL_IO.Header Header;
|
||||
|
||||
public void Load(System.IO.Stream stream)
|
||||
{
|
||||
Text = FileName;
|
||||
CanSave = true;
|
||||
|
||||
using (var reader = new FileReader(stream))
|
||||
{
|
||||
reader.SetByteOrder(true);
|
||||
|
||||
Header = new TPL_IO.Header();
|
||||
Header.Read(reader);
|
||||
|
||||
foreach (var tex in Header.Images) {
|
||||
var texWrapper = new TplTextureWrapper(this, tex.Header);
|
||||
texWrapper.PaletteHeader = tex.PaletteHeader;
|
||||
texWrapper.ImageKey = "Texture";
|
||||
texWrapper.SelectedImageKey = "Texture";
|
||||
texWrapper.Format = Decode_Gamecube.ToGenericFormat(tex.Header.Format);
|
||||
texWrapper.Width = tex.Header.Width;
|
||||
texWrapper.Height = tex.Header.Height;
|
||||
texWrapper.ImageData = tex.ImageData;
|
||||
texWrapper.MipCount = tex.Header.MaxLOD;
|
||||
texWrapper.PlatformSwizzle = PlatformSwizzle.Platform_Gamecube;
|
||||
Nodes.Add(texWrapper);
|
||||
|
||||
if (tex.PaletteHeader != null)
|
||||
{
|
||||
var GXPaletteFormat = (Decode_Gamecube.PaletteFormats)tex.PaletteHeader.PaletteFormat;
|
||||
texWrapper.SetPaletteData(tex.PaletteHeader.Data, Decode_Gamecube.ToGenericPaletteFormat(GXPaletteFormat));
|
||||
}
|
||||
}
|
||||
|
||||
UpdateDisplayedNames();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDisplayedNames() {
|
||||
string name = System.IO.Path.GetFileNameWithoutExtension(FileName);
|
||||
|
||||
int i = 0;
|
||||
foreach (TplTextureWrapper tex in Nodes)
|
||||
{
|
||||
if (Header.Images.Count == 1)
|
||||
tex.Text = name;
|
||||
else
|
||||
tex.Text = $"{name}_{i++}";
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(System.IO.Stream stream)
|
||||
{
|
||||
using (var writer = new FileWriter(stream)) {
|
||||
writer.SetByteOrder(true);
|
||||
Header.Write(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public class TplTextureWrapper : STGenericTexture
|
||||
{
|
||||
public TPL TPLParent { get; set; }
|
||||
|
||||
public byte[] ImageData { get; set; }
|
||||
public TPL_IO.TPLImageHeader ImageHeader;
|
||||
public TPL_IO.PaletteHeader PaletteHeader;
|
||||
|
||||
public TplTextureWrapper() { }
|
||||
|
||||
public TplTextureWrapper(TPL tpl) {
|
||||
TPLParent = tpl;
|
||||
}
|
||||
|
||||
public TplTextureWrapper(TPL tpl, TPL_IO.TPLImageHeader header) {
|
||||
TPLParent = tpl;
|
||||
ImageHeader = header;
|
||||
|
||||
CanReplace = true;
|
||||
}
|
||||
|
||||
public override string ExportFilter => FileFilters.REV_TEX;
|
||||
public override string ReplaceFilter => FileFilters.REV_TEX;
|
||||
|
||||
public override TEX_FORMAT[] SupportedFormats
|
||||
{
|
||||
get
|
||||
{
|
||||
return new TEX_FORMAT[]
|
||||
{
|
||||
TEX_FORMAT.I4,
|
||||
TEX_FORMAT.I8,
|
||||
TEX_FORMAT.IA4,
|
||||
TEX_FORMAT.IA8,
|
||||
TEX_FORMAT.RGB565,
|
||||
TEX_FORMAT.RGB5A3,
|
||||
TEX_FORMAT.RGBA32,
|
||||
TEX_FORMAT.C4,
|
||||
TEX_FORMAT.C8,
|
||||
TEX_FORMAT.C14X2,
|
||||
TEX_FORMAT.CMPR,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override bool CanEdit { get; set; } = true;
|
||||
|
||||
public override void SetImageData(System.Drawing.Bitmap bitmap, int ArrayLevel)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0, int DepthLevel = 0)
|
||||
{
|
||||
return Decode_Gamecube.GetMipLevel(ImageData, Width, Height, MipCount, (uint)MipLevel, Format);
|
||||
}
|
||||
|
||||
public override void OnClick(TreeView treeView)
|
||||
{
|
||||
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase));
|
||||
if (editor == null)
|
||||
{
|
||||
editor = new ImageEditorBase();
|
||||
editor.Dock = DockStyle.Fill;
|
||||
LibraryGUI.LoadEditor(editor);
|
||||
}
|
||||
|
||||
editor.LoadProperties(ImageHeader);
|
||||
editor.LoadImage(this);
|
||||
}
|
||||
|
||||
public void UpdateEditor()
|
||||
{
|
||||
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase));
|
||||
if (editor == null)
|
||||
{
|
||||
editor = new ImageEditorBase();
|
||||
editor.Dock = DockStyle.Fill;
|
||||
LibraryGUI.LoadEditor(editor);
|
||||
}
|
||||
|
||||
editor.LoadProperties(GenericProperties);
|
||||
editor.LoadImage(this);
|
||||
}
|
||||
|
||||
public static TplTextureWrapper Create(TPL tpl, TPL_IO.Header header, string FileName)
|
||||
{
|
||||
TplTextureWrapper tex = new TplTextureWrapper(tpl);
|
||||
tex.Replace(FileName);
|
||||
if (tex.ImageData == null) //Dialog cancelled if image data not set
|
||||
return null;
|
||||
tex.ImageHeader.Width = (ushort)tex.Width;
|
||||
tex.ImageHeader.Height = (ushort)tex.Height;
|
||||
tex.ImageHeader.Format = Decode_Gamecube.FromGenericFormat(tex.Format);
|
||||
tex.ImageHeader.MaxLOD = (byte)tex.MipCount;
|
||||
header.Images.Add(new TPL_IO.ImageEntry()
|
||||
{
|
||||
Header= tex.ImageHeader,
|
||||
ImageData = tex.ImageData,
|
||||
PaletteHeader = tex.PaletteHeader,
|
||||
});
|
||||
return tex;
|
||||
}
|
||||
|
||||
public override void Replace(string FileName)
|
||||
{
|
||||
GamecubeTextureImporterList importer = new GamecubeTextureImporterList(SupportedFormats);
|
||||
GameCubeTextureImporterSettings settings = new GameCubeTextureImporterSettings();
|
||||
|
||||
importer.ForceMipCount = true;
|
||||
if (MipCount == 1)
|
||||
importer.SelectedMipCount = 1;
|
||||
|
||||
if (Utils.GetExtension(FileName) == ".dds" ||
|
||||
Utils.GetExtension(FileName) == ".dds2")
|
||||
{
|
||||
settings.LoadDDS(FileName);
|
||||
importer.LoadSettings(new List<GameCubeTextureImporterSettings>() { settings, });
|
||||
|
||||
ApplySettings(settings);
|
||||
UpdateEditor();
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.LoadBitMap(FileName);
|
||||
importer.LoadSettings(new List<GameCubeTextureImporterSettings>() { settings, });
|
||||
|
||||
if (importer.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
if (settings.GenerateMipmaps && !settings.IsFinishedCompressing)
|
||||
settings.Compress();
|
||||
|
||||
ApplySettings(settings);
|
||||
UpdateEditor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplySettings(GameCubeTextureImporterSettings settings)
|
||||
{
|
||||
if (ImageHeader == null)
|
||||
ImageHeader = new TPL_IO.ImageHeaderV2();
|
||||
|
||||
this.ImageData = settings.DataBlockOutput[0];
|
||||
this.Width = settings.TexWidth;
|
||||
this.Height = settings.TexHeight;
|
||||
this.Format = settings.GenericFormat;
|
||||
this.MipCount = settings.MipCount;
|
||||
this.Depth = 1; //Always 1
|
||||
this.ArrayCount = 1;
|
||||
UpdateHeader();
|
||||
|
||||
if (this.RenderableTex != null)
|
||||
this.LoadOpenGLTexture();
|
||||
}
|
||||
|
||||
private void UpdateHeader() {
|
||||
ImageHeader.Width = (ushort)Width;
|
||||
ImageHeader.Height = (ushort)Height;
|
||||
ImageHeader.MaxLOD = MipCount == 1 ? (byte)0 : (byte)MipCount;
|
||||
ImageHeader.Format = Decode_Gamecube.FromGenericFormat(Format);
|
||||
}
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
299
File_Format_Library/FileFormats/Texture/TPL/TPL_IO.cs
Normal file
299
File_Format_Library/FileFormats/Texture/TPL/TPL_IO.cs
Normal file
|
@ -0,0 +1,299 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.ComponentModel;
|
||||
using Toolbox.Library;
|
||||
using Toolbox.Library.IO;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
public class TPL_IO
|
||||
{
|
||||
public class Header
|
||||
{
|
||||
public List<ImageEntry> Images = new List<ImageEntry>();
|
||||
|
||||
public bool IsV1 = false;
|
||||
|
||||
public void Read(FileReader reader)
|
||||
{
|
||||
reader.SetByteOrder(true);
|
||||
uint Identifier = reader.ReadUInt32();
|
||||
if (Identifier != 0x0020AF30) {
|
||||
IsV1 = true;
|
||||
|
||||
reader.Position = 0;
|
||||
uint ImageCount = reader.ReadUInt32();
|
||||
for (int i = 0; i < ImageCount; i++) {
|
||||
reader.SeekBegin(4 + (i * 0x10));
|
||||
ImageEntry image = new ImageEntry();
|
||||
image.Header = new ImageHeaderV1(reader);
|
||||
image.ImageData = GetImageData(reader, image.Header);
|
||||
Images.Add(image);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint ImageCount = reader.ReadUInt32();
|
||||
uint ImageOffsetTable = reader.ReadUInt32();
|
||||
for (int i = 0; i < ImageCount; i++) {
|
||||
reader.SeekBegin(ImageOffsetTable + (i * 8));
|
||||
|
||||
ImageEntry image = new ImageEntry();
|
||||
|
||||
uint ImageHeaderOffset = reader.ReadUInt32();
|
||||
uint PaletteHeaderOffset = reader.ReadUInt32();
|
||||
|
||||
reader.SeekBegin(ImageHeaderOffset);
|
||||
image.Header = new ImageHeaderV2(reader);
|
||||
image.ImageData = GetImageData(reader, image.Header);
|
||||
Images.Add(image);
|
||||
|
||||
if (PaletteHeaderOffset != 0) {
|
||||
reader.SeekBegin(PaletteHeaderOffset);
|
||||
image.PaletteHeader = new PaletteHeader(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(FileWriter writer)
|
||||
{
|
||||
writer.SetByteOrder(true);
|
||||
if (IsV1) {
|
||||
writer.Write(Images.Count);
|
||||
for (int i = 0; i < Images.Count; i++)
|
||||
((ImageHeaderV1)Images[i].Header).Write(writer);
|
||||
|
||||
AlignBytesIncrement(writer, 32);
|
||||
for (int i = 0; i < Images.Count; i++) {
|
||||
writer.WriteUint32Offset(8 + (i * 0x10));
|
||||
writer.Write(Images[i].ImageData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(0x0020AF30);
|
||||
writer.Write(Images.Count);
|
||||
writer.Write(0x0C); //Offset always 12
|
||||
|
||||
//Reserve space for palette and header offsets
|
||||
writer.Write(new byte[Images.Count * 8]);
|
||||
|
||||
//Then write the palettes first
|
||||
for (int i = 0; i < Images.Count; i++)
|
||||
{
|
||||
if (Images[i].PaletteHeader != null) {
|
||||
writer.WriteUint32Offset(16 + (i * 8));
|
||||
Images[i].PaletteHeader.Write(writer);
|
||||
}
|
||||
}
|
||||
|
||||
//Then write the headers
|
||||
long imageHeaderPos = writer.Position;
|
||||
for (int i = 0; i < Images.Count; i++)
|
||||
{
|
||||
writer.WriteUint32Offset(12 + (i * 8));
|
||||
((ImageHeaderV2)Images[i].Header).Write(writer);
|
||||
}
|
||||
|
||||
//Then write the data
|
||||
for (int i = 0; i < Images.Count; i++)
|
||||
{
|
||||
writer.Align(64);
|
||||
writer.WriteUint32Offset(imageHeaderPos + 8 + (i * 0x24));
|
||||
writer.Write(Images[i].ImageData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AlignBytesIncrement(FileWriter writer, int alignment)
|
||||
{
|
||||
var startPos = writer.Position;
|
||||
long position = writer.Seek((-writer.Position % alignment + alignment) % alignment, SeekOrigin.Current);
|
||||
|
||||
byte value = 0;
|
||||
|
||||
writer.Seek(startPos, System.IO.SeekOrigin.Begin);
|
||||
while (writer.Position != position) {
|
||||
writer.Write(value++);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] GetImageData(FileReader reader, TPLImageHeader image)
|
||||
{
|
||||
return reader.getSection(image.ImageOffset,
|
||||
(uint)Decode_Gamecube.GetDataSizeWithMips(image.Format, image.Width, image.Height, image.MaxLOD));
|
||||
}
|
||||
|
||||
public class ImageEntry
|
||||
{
|
||||
public PaletteHeader PaletteHeader;
|
||||
public TPLImageHeader Header;
|
||||
public byte[] ImageData;
|
||||
}
|
||||
|
||||
public interface TPLImageHeader
|
||||
{
|
||||
Decode_Gamecube.TextureFormats Format { get; set; }
|
||||
uint ImageOffset { get; set; }
|
||||
ushort Width { get; set; }
|
||||
ushort Height { get; set; }
|
||||
byte MinLOD { get; set; }
|
||||
byte MaxLOD { get; set; }
|
||||
}
|
||||
|
||||
//TPL has 2 versions
|
||||
//V1 is used for some gc games
|
||||
|
||||
public class ImageHeaderV1 : TPLImageHeader
|
||||
{
|
||||
[ReadOnly(true)]
|
||||
public Decode_Gamecube.TextureFormats Format { get; set; }
|
||||
[Browsable(false)]
|
||||
public uint ImageOffset { get; set; }
|
||||
[ReadOnly(true)]
|
||||
public ushort Width { get; set; }
|
||||
[ReadOnly(true)]
|
||||
public ushort Height { get; set; }
|
||||
[ReadOnly(true)]
|
||||
public byte MinLOD { get; set; }
|
||||
[ReadOnly(true)]
|
||||
public byte MaxLOD { get; set; }
|
||||
[ReadOnly(true)]
|
||||
public ushort Unknown { get; set; }
|
||||
|
||||
public ImageHeaderV1() { }
|
||||
|
||||
public ImageHeaderV1(FileReader reader)
|
||||
{
|
||||
Format = (Decode_Gamecube.TextureFormats)reader.ReadUInt32();
|
||||
ImageOffset = reader.ReadUInt32();
|
||||
Width = reader.ReadUInt16();
|
||||
Height = reader.ReadUInt16();
|
||||
MinLOD = reader.ReadByte();
|
||||
MaxLOD = reader.ReadByte();
|
||||
Unknown = reader.ReadUInt16();
|
||||
}
|
||||
|
||||
public void Write(FileWriter writer)
|
||||
{
|
||||
writer.Write((uint)Format);
|
||||
writer.Write(ImageOffset);
|
||||
writer.Write(Width);
|
||||
writer.Write(Height);
|
||||
writer.Write(MinLOD);
|
||||
writer.Write(MaxLOD);
|
||||
writer.Write(Unknown);
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageHeaderV2 : TPLImageHeader
|
||||
{
|
||||
[ReadOnly(true)]
|
||||
public ushort Width { get; set; }
|
||||
[ReadOnly(true)]
|
||||
public ushort Height { get; set; }
|
||||
[ReadOnly(true)]
|
||||
public Decode_Gamecube.TextureFormats Format { get; set; }
|
||||
[Browsable(false)]
|
||||
public uint ImageOffset { get; set; }
|
||||
|
||||
public WrapMode WrapS { get; set; }
|
||||
public WrapMode WrapT { get; set; }
|
||||
public FilterMode MinFilter { get; set; }
|
||||
public FilterMode MagFilter { get; set; }
|
||||
|
||||
public float LODBias { get; set; }
|
||||
public bool EdgeLODEnable { get; set; }
|
||||
[ReadOnly(true)]
|
||||
public byte MinLOD { get; set; }
|
||||
[ReadOnly(true)]
|
||||
public byte MaxLOD { get; set; }
|
||||
[ReadOnly(true)]
|
||||
public byte Unpacked { get; set; }
|
||||
|
||||
public ImageHeaderV2() { }
|
||||
|
||||
public ImageHeaderV2(FileReader reader)
|
||||
{
|
||||
Height = reader.ReadUInt16();
|
||||
Width = reader.ReadUInt16();
|
||||
Format = (Decode_Gamecube.TextureFormats)reader.ReadUInt32();
|
||||
ImageOffset = reader.ReadUInt32();
|
||||
WrapS = (WrapMode)reader.ReadUInt32();
|
||||
WrapT = (WrapMode)reader.ReadUInt32();
|
||||
MinFilter = (FilterMode)reader.ReadUInt32();
|
||||
MagFilter = (FilterMode)reader.ReadUInt32();
|
||||
LODBias = reader.ReadSingle();
|
||||
EdgeLODEnable = reader.ReadBoolean();
|
||||
MinLOD = reader.ReadByte();
|
||||
MaxLOD = reader.ReadByte();
|
||||
Unpacked = reader.ReadByte();
|
||||
}
|
||||
|
||||
public void Write(FileWriter writer)
|
||||
{
|
||||
writer.Write(Height);
|
||||
writer.Write(Width);
|
||||
writer.Write((uint)Format);
|
||||
writer.Write(ImageOffset);
|
||||
writer.Write((uint)WrapS);
|
||||
writer.Write((uint)WrapT);
|
||||
writer.Write((uint)MinFilter);
|
||||
writer.Write((uint)MagFilter);
|
||||
writer.Write(LODBias);
|
||||
writer.Write(EdgeLODEnable);
|
||||
writer.Write(MinLOD);
|
||||
writer.Write(MaxLOD);
|
||||
writer.Write(Unpacked);
|
||||
}
|
||||
}
|
||||
|
||||
public class PaletteHeader
|
||||
{
|
||||
public ushort EntryCount { get; set; }
|
||||
public byte Unpacked { get; set; }
|
||||
public uint PaletteFormat { get; set; }
|
||||
public uint PaletteDataOffset { get; set; }
|
||||
|
||||
public byte[] Data;
|
||||
|
||||
public PaletteHeader(FileReader reader) {
|
||||
EntryCount = reader.ReadUInt16();
|
||||
Unpacked = reader.ReadByte();
|
||||
reader.ReadByte();
|
||||
PaletteFormat = reader.ReadUInt32();
|
||||
PaletteDataOffset = reader.ReadUInt32();
|
||||
|
||||
using (reader.TemporarySeek(PaletteDataOffset, SeekOrigin.Begin)) {
|
||||
Data = reader.ReadBytes(EntryCount * 2);
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(FileWriter writer) {
|
||||
writer.Write(EntryCount);
|
||||
writer.Write(Unpacked);
|
||||
writer.Write((byte)0);
|
||||
writer.Write(PaletteFormat);
|
||||
writer.Write(PaletteDataOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public enum WrapMode : uint
|
||||
{
|
||||
Clamp,
|
||||
Repeat,
|
||||
Mirror
|
||||
}
|
||||
|
||||
public enum FilterMode : uint
|
||||
{
|
||||
Nearest,
|
||||
Linear,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -458,8 +458,9 @@
|
|||
<Compile Include="FileFormats\Texture\CTPK.cs" />
|
||||
<Compile Include="FileFormats\Grezzo\CTXB.cs" />
|
||||
<Compile Include="FileFormats\Texture\SIR0.cs" />
|
||||
<Compile Include="FileFormats\Texture\TPL\TPL_IO.cs" />
|
||||
<Compile Include="FileFormats\Texture\TVOL.cs" />
|
||||
<Compile Include="FileFormats\Texture\TPL.cs" />
|
||||
<Compile Include="FileFormats\Texture\TPL\TPL.cs" />
|
||||
<Compile Include="FileFormats\Rom\GCDisk.cs" />
|
||||
<Compile Include="FileFormats\Texture\BTI.cs" />
|
||||
<Compile Include="FileFormats\Texture\WTB.cs" />
|
||||
|
|
Loading…
Reference in a new issue