Add support for basic BTI and TXE

This commit is contained in:
JohnFiddleystein 2019-08-04 14:15:34 +01:00
parent 1f8bd2e19e
commit dd33b5e6c5
16 changed files with 390 additions and 34 deletions

BIN
.vs/Toolbox/v16/.suo Normal file

Binary file not shown.

View file

Binary file not shown.

View file

@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Toolbox.Library;
using Toolbox.Library.Forms;
using Toolbox.Library.IO;
namespace AmbrosiaPikmin1.FileFormats.BTI
{
class BTI : TreeNodeFile, IFileFormat
{
public FileType FileType { get; set; } = FileType.Image;
public bool CanSave { get; set; }
public string[] Description { get; set; } = new string[] { "Binary Texture Image" };
public string[] Extension { get; set; } = new string[] { "*.bti" };
public string FileName { get; set; }
public string FilePath { get; set; }
//Stores compression info from being opened (done automaitcally)
public IFileInfo IFileInfo { get; set; }
//Check how the file wil be opened
public bool Identify(System.IO.Stream stream)
{
return Utils.HasExtension(FileName, ".bti");
}
//A Type list for custom types
//With this you can add in classes with IFileMenuExtension to add menus for this format
public Type[] Types
{
get
{
List<Type> types = new List<Type>();
return types.ToArray();
}
}
private int RoundWidth(int width, int BlockWidth)
{
return width + ((BlockWidth - (width % BlockWidth)) % BlockWidth);
}
private int RoundHeight(int height, int BlockHeight)
{
return height + ((BlockHeight - (height % BlockHeight)) % BlockHeight);
}
public void Load(System.IO.Stream stream)
{
//Set this if you want to save the file format
CanSave = true;
//You can add a FileReader with Toolbox.Library.IO namespace
using (var reader = new FileReader(stream))
{
Texture tex = new Texture();
tex.CanEdit = false;
reader.SetByteOrder(true);
//Turn this format into a common format used by this tool
byte texFormat = reader.ReadByte();
tex.Format = Decode_Gamecube.ToGenericFormat((Decode_Gamecube.TextureFormats)texFormat);
_ = reader.ReadByte(); // enable alpha
tex.Width = reader.ReadUInt16();
tex.Height = reader.ReadUInt16();
_ = reader.ReadByte(); // wrap s
_ = reader.ReadByte(); // wrap t
tex.PaletteFormat = (PALETTE_FORMAT)reader.ReadInt16();
_ = reader.ReadInt16(); // num of palette entries
_ = reader.ReadInt32(); // offset to palette data
_ = reader.ReadInt32(); // border colour
_ = reader.ReadByte(); // min filter type
_ = reader.ReadByte(); // mag filter type
_ = reader.ReadInt16();
tex.MipCount = reader.ReadByte();
_ = reader.ReadByte();
_ = reader.ReadInt16();
uint offsetToImageData = reader.ReadUInt32(); // offset to image data
//Lets set our method of decoding
tex.PlatformSwizzle = PlatformSwizzle.Platform_Gamecube;
reader.Seek(offsetToImageData, System.IO.SeekOrigin.Begin);
int imageDataSize = RoundWidth((int)tex.Width, (int)STGenericTexture.GetBlockWidth(tex.Format)) * RoundHeight((int)tex.Height, (int)STGenericTexture.GetBlockHeight(tex.Format))
* (int)STGenericTexture.GetBytesPerPixel(tex.Format) >> 3;
tex.ImageData = reader.ReadBytes(imageDataSize);
tex.Name = FileName;
tex.ToolTipText = "Binary Texture Image, used for 2D textures like fonts";
_ = Nodes.Add(tex);
}
}
public byte[] Save()
{
return null;
}
public void Unload()
{
}
public class Texture : STGenericTexture
{
public byte[] ImageData { get; set; }
//A list of supported formats
//This gets used in the re encode option
public override TEX_FORMAT[] SupportedFormats
{
get
{
return new TEX_FORMAT[]
{
TEX_FORMAT.I4,
TEX_FORMAT.I8,
TEX_FORMAT.I4,
TEX_FORMAT.I8,
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;
//This gets used in the image editor if the image gets edited
//This wll not be ran if "CanEdit" is set to false!
public override void SetImageData(System.Drawing.Bitmap bitmap, int ArrayLevel)
{
}
//Gets the raw image data in bytes
//Gets decoded automatically
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0)
{
return ImageData;
}
//This is an event for when the tree is clicked on
//Load our editor
public override void OnClick(TreeView treeView)
{
//Here we check for an active editor and load a new one if not found
//This is used when a tree/object editor is used
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase));
if (editor == null)
{
editor = new ImageEditorBase();
editor.Dock = DockStyle.Fill;
LibraryGUI.LoadEditor(editor);
}
//Load our image and any properties
//If you don't make a class for properties you can use a generic class provided in STGenericTexture
editor.LoadProperties(GenericProperties);
editor.LoadImage(this);
}
}
}
}

View file

@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Toolbox.Library;
using Toolbox.Library.Forms;
using Toolbox.Library.IO;
namespace AmbrosiaPikmin1.FileFormats.TXE
{
class TXE : TreeNodeFile, IFileFormat
{
public FileType FileType { get; set; } = FileType.Image;
public bool CanSave { get; set; }
public string[] Description { get; set; } = new string[] { "Pikmin 1 Proprietary Texture" };
public string[] Extension { get; set; } = new string[] { "*.txe" };
public string FileName { get; set; }
public string FilePath { get; set; }
//Stores compression info from being opened (done automaitcally)
public IFileInfo IFileInfo { get; set; }
//Check how the file wil be opened
public bool Identify(System.IO.Stream stream)
{
return Utils.HasExtension(FileName, ".txe");
}
//A Type list for custom types
//With this you can add in classes with IFileMenuExtension to add menus for this format
public Type[] Types
{
get
{
List<Type> types = new List<Type>();
return types.ToArray();
}
}
private void SkipPadding(FileReader stream, int offset)
{
stream.Seek((~(offset - 1) & (stream.Position + offset - 1)) - stream.Position);
}
public void Load(System.IO.Stream stream)
{
//Set this if you want to save the file format
CanSave = true;
//You can add a FileReader with Toolbox.Library.IO namespace
using (var reader = new FileReader(stream))
{
Texture tex = new Texture();
tex.CanEdit = false;
reader.SetByteOrder(true);
tex.Width = reader.ReadUInt16();
tex.Height = reader.ReadUInt16();
_ = reader.ReadInt16();
//Turn this format into a common format used by this tool
short texFormat = reader.ReadInt16();
tex.Format = Decode_Gamecube.ToGenericFormat((Decode_Gamecube.TextureFormats)texFormat);
//Lets set our method of decoding
tex.PlatformSwizzle = PlatformSwizzle.Platform_Gamecube;
int imageDataSize = reader.ReadInt32();
SkipPadding(reader, 0x20);
tex.ImageData = reader.ReadBytes(imageDataSize);
tex.Name = FileName;
tex.ToolTipText = "Binary Texture Image, used for 2D textures like fonts";
_ = Nodes.Add(tex);
}
}
public byte[] Save()
{
return null;
}
public void Unload()
{
}
public class Texture : STGenericTexture
{
public byte[] ImageData { get; set; }
//A list of supported formats
//This gets used in the re encode option
public override TEX_FORMAT[] SupportedFormats
{
get
{
return new TEX_FORMAT[]
{
TEX_FORMAT.I4,
TEX_FORMAT.I8,
TEX_FORMAT.I4,
TEX_FORMAT.I8,
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;
//This gets used in the image editor if the image gets edited
//This wll not be ran if "CanEdit" is set to false!
public override void SetImageData(System.Drawing.Bitmap bitmap, int ArrayLevel)
{
}
//Gets the raw image data in bytes
//Gets decoded automatically
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0)
{
return ImageData;
}
//This is an event for when the tree is clicked on
//Load our editor
public override void OnClick(TreeView treeView)
{
//Here we check for an active editor and load a new one if not found
//This is used when a tree/object editor is used
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase));
if (editor == null)
{
editor = new ImageEditorBase();
editor.Dock = DockStyle.Fill;
LibraryGUI.LoadEditor(editor);
}
//Load our image and any properties
//If you don't make a class for properties you can use a generic class provided in STGenericTexture
editor.LoadProperties(GenericProperties);
editor.LoadImage(this);
}
}
}
}

View file

@ -275,10 +275,12 @@
<Compile Include="FileFormats\Font\BFTTF.cs" />
<Compile Include="FileFormats\HyruleWarriors\G1M.cs" />
<Compile Include="FileFormats\Message\MSBP.cs" />
<Compile Include="FileFormats\Texture\TXE.cs" />
<Compile Include="FileFormats\Texture\CTPK.cs" />
<Compile Include="FileFormats\Grezzo\CTXB.cs" />
<Compile Include="FileFormats\Texture\TPL.cs" />
<Compile Include="FileFormats\Rom\GCDisk.cs" />
<Compile Include="FileFormats\Texture\BTI.cs" />
<Compile Include="GL\BMD_Renderer.cs" />
<Compile Include="GL\CMB_Renderer.cs" />
<Compile Include="GL\GXToOpenGL.cs" />

View file

@ -8,6 +8,8 @@ using Toolbox.Library.Forms;
using Toolbox.Library.IO;
using FirstPlugin.Forms;
using FirstPlugin.LuigisMansion.DarkMoon;
using AmbrosiaPikmin1.FileFormats.BTI;
using AmbrosiaPikmin1.FileFormats.TXE;
namespace FirstPlugin
{
@ -287,6 +289,8 @@ namespace FirstPlugin
private Type[] LoadFileFormats()
{
List<Type> Formats = new List<Type>();
Formats.Add(typeof(BTI));
Formats.Add(typeof(TXE));
Formats.Add(typeof(SARC));
Formats.Add(typeof(BFRES));
Formats.Add(typeof(BCRES));

View file

@ -188,5 +188,7 @@ namespace Toolbox.Library
C8 = 247,
C14X2 = 248,
CMPR = 249,
RGB565 = 250,
RGB5A3 = 251
}
}

View file

@ -103,7 +103,7 @@ namespace Toolbox.Library
//
//Gets a list of surfaces given the start index of the array and the amount of arrays to obtain
//
public List<Surface> GetSurfaces(int ArrayIndexStart = 0, bool GetAllSurfaces = true, int GetSurfaceAmount = 1 )
public List<Surface> GetSurfaces(int ArrayIndexStart = 0, bool GetAllSurfaces = true, int GetSurfaceAmount = 1)
{
if (GetAllSurfaces)
GetSurfaceAmount = (int)ArrayCount;
@ -146,7 +146,8 @@ namespace Toolbox.Library
public uint MipCount
{
get { return mipCount; }
set {
set
{
if (value == 0)
mipCount = 1;
else if (value > 17)
@ -184,7 +185,7 @@ namespace Toolbox.Library
public RenderableTex RenderableTex { get; set; }
public abstract TEX_FORMAT[] SupportedFormats { get;}
public abstract TEX_FORMAT[] SupportedFormats { get; }
public static uint GetBytesPerPixel(TEX_FORMAT Format)
{
@ -212,7 +213,7 @@ namespace Toolbox.Library
private static readonly Dictionary<TEX_FORMAT, FormatInfo> FormatTable =
new Dictionary<TEX_FORMAT, FormatInfo>()
{
{
{ TEX_FORMAT.R32G32B32A32_FLOAT, new FormatInfo(16, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.R32G32B32A32_SINT, new FormatInfo(16, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.R32G32B32A32_UINT, new FormatInfo(16, 1, 1, 1, TargetBuffer.Color) },
@ -314,11 +315,24 @@ namespace Toolbox.Library
{ TEX_FORMAT.A4, new FormatInfo(4, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.A8_UNORM, new FormatInfo(8, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.D16_UNORM, new FormatInfo(2, 1, 1, 1, TargetBuffer.Depth) },
{ TEX_FORMAT.D24_UNORM_S8_UINT, new FormatInfo(4, 1, 1, 1, TargetBuffer.Depth) },
{ TEX_FORMAT.D32_FLOAT, new FormatInfo(4, 1, 1, 1, TargetBuffer.Depth) },
{ TEX_FORMAT.D32_FLOAT_S8X24_UINT, new FormatInfo(8, 1, 1, 1,TargetBuffer.DepthStencil) }
};
{ TEX_FORMAT.D16_UNORM, new FormatInfo(2, 1, 1, 1, TargetBuffer.Depth) },
{ TEX_FORMAT.D24_UNORM_S8_UINT, new FormatInfo(4, 1, 1, 1, TargetBuffer.Depth) },
{ TEX_FORMAT.D32_FLOAT, new FormatInfo(4, 1, 1, 1, TargetBuffer.Depth) },
{ TEX_FORMAT.D32_FLOAT_S8X24_UINT, new FormatInfo(8, 1, 1, 1, TargetBuffer.DepthStencil)},
{ TEX_FORMAT.I4, new FormatInfo(4, 8, 8, 1, TargetBuffer.Color) },
{ TEX_FORMAT.I8, new FormatInfo(8, 8, 4, 1, TargetBuffer.Color) },
{ TEX_FORMAT.IA4, new FormatInfo(8, 8, 4, 1, TargetBuffer.Color) },
{ TEX_FORMAT.IA8, new FormatInfo(16, 4, 4, 1, TargetBuffer.Color) },
{ TEX_FORMAT.RGB565, new FormatInfo(16, 4, 4, 1, TargetBuffer.Color) },
{ TEX_FORMAT.RGB5A3, new FormatInfo(16, 4, 4, 1, TargetBuffer.Color) },
{ TEX_FORMAT.RGBA32, new FormatInfo(32, 4, 4, 1, TargetBuffer.Color) },
{ TEX_FORMAT.C4, new FormatInfo(4, 8, 8, 1, TargetBuffer.Color) },
{ TEX_FORMAT.C8, new FormatInfo(8, 8, 4, 1, TargetBuffer.Color) },
{ TEX_FORMAT.C14X2, new FormatInfo(16, 4, 4, 1, TargetBuffer.Color) },
{ TEX_FORMAT.CMPR, new FormatInfo(4, 8, 8, 1, TargetBuffer.Color) }
};
/// <summary>
/// A Surface contains mip levels of compressed/uncompressed texture data
@ -328,7 +342,7 @@ namespace Toolbox.Library
public List<byte[]> mipmaps = new List<byte[]>();
}
public void CreateGenericTexture(uint width, uint height, List<Surface> surfaces, TEX_FORMAT format )
public void CreateGenericTexture(uint width, uint height, List<Surface> surfaces, TEX_FORMAT format)
{
Width = width;
Height = height;
@ -383,15 +397,16 @@ namespace Toolbox.Library
byte[] data = GetImageData(ArrayLevel, MipLevel);
byte[] paletteData = GetPaletteData();
if (data.Length == 0)
return new Bitmap(1,1);
return new Bitmap(1, 1);
try
{
if (data == null)
throw new Exception("Data is null!");
if (PlatformSwizzle == PlatformSwizzle.Platform_3DS && !IsCompressed(Format)) {
var Image = BitmapExtension.GetBitmap(ConvertBgraToRgba(CTR_3DS.DecodeBlock(data, (int)width, (int)height, Format)),
if (PlatformSwizzle == PlatformSwizzle.Platform_3DS && !IsCompressed(Format))
{
var Image = BitmapExtension.GetBitmap(ConvertBgraToRgba(CTR_3DS.DecodeBlock(data, (int)width, (int)height, Format)),
(int)width, (int)height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Image.RotateFlip(RotateFlipType.RotateNoneFlipY); //It's upside down for some reason so flip it
return Image;
@ -506,11 +521,11 @@ namespace Toolbox.Library
/// <returns>Returns a byte array of decoded data. </returns>
public static byte[] DecodeBlock(byte[] data, uint Width, uint Height, TEX_FORMAT Format, byte[] paletteData, ImageParameters parameters, PALETTE_FORMAT PaletteFormat = PALETTE_FORMAT.None, PlatformSwizzle PlatformSwizzle = PlatformSwizzle.None)
{
if (data == null) throw new Exception($"Data is null!");
if (Format <= 0) throw new Exception($"Invalid Format!");
if (data == null) throw new Exception($"Data is null!");
if (Format <= 0) throw new Exception($"Invalid Format!");
if (data.Length <= 0) throw new Exception($"Data is empty!");
if (Width <= 0) throw new Exception($"Invalid width size {Width}!");
if (Height <= 0) throw new Exception($"Invalid height size {Height}!");
if (Width <= 0) throw new Exception($"Invalid width size {Width}!");
if (Height <= 0) throw new Exception($"Invalid height size {Height}!");
byte[] imageData = new byte[0];
bool DontSwapRG = false;
@ -552,7 +567,7 @@ namespace Toolbox.Library
public string DebugInfo()
{
return $"Texture Info:\n" +
$"Name: {Text}\n" +
$"Name: {Text}\n" +
$"Format: {Format}\n" +
$"Height: {Height}\n" +
$"Width: {Width}\n" +
@ -566,7 +581,7 @@ namespace Toolbox.Library
public uint GenerateMipCount(int Width, int Height)
{
return GenerateMipCount((uint)Width, (uint)Height);
return GenerateMipCount((uint)Width, (uint)Height);
}
public uint GenerateMipCount(uint Width, uint Height)
@ -686,7 +701,8 @@ namespace Toolbox.Library
}
}
public override void Export(string FileName) {
public override void Export(string FileName)
{
Export(FileName);
}
@ -712,7 +728,7 @@ namespace Toolbox.Library
if (sfd.ShowDialog() == DialogResult.OK)
{
Export(sfd.FileName, false, false, 0,0);
Export(sfd.FileName, false, false, 0, 0);
}
}
@ -757,7 +773,7 @@ namespace Toolbox.Library
public void SaveTGA(string FileName, bool ExportSurfaceLevel = false,
bool ExportMipMapLevel = false, int SurfaceLevel = 0, int MipLevel = 0)
{
}
public void SaveBitMap(string FileName, bool ExportSurfaceLevel = false,
bool ExportMipMapLevel = false, int SurfaceLevel = 0, int MipLevel = 0)
@ -773,7 +789,7 @@ namespace Toolbox.Library
{
progressBar.Task = "Select dialog option... ";
var result = MessageBox.Show("Multiple image surfaces found! Would you like to export them all?", "Image Exporter",
var result = MessageBox.Show("Multiple image surfaces found! Would you like to export them all?", "Image Exporter",
MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
if (result == DialogResult.Yes)
{
@ -798,7 +814,7 @@ namespace Toolbox.Library
return;
}
}
}
progressBar.Task = $"Decoding image {Text}... ";
progressBar.Value = 20;
@ -946,9 +962,9 @@ namespace Toolbox.Library
if (width > 1)
width /= 2;
if (height > 1)
height /= 2;
height /= 2;
}
return mipCount;
@ -996,7 +1012,7 @@ namespace Toolbox.Library
int pixel = 0;
for (int i = 0; i < bpp; i += 1)
pixel |= bytes[pos + i] << (8 * i);
comp = GetComponentsFromPixel(Format, pixel, comp);
NewImageData[pos_ + 3] = comp[compSel[3]];

Binary file not shown.

Binary file not shown.

View file

@ -27,9 +27,9 @@ namespace Toolbox.Library
case TextureFormats.I8: return TEX_FORMAT.I8;
case TextureFormats.IA4: return TEX_FORMAT.IA4;
case TextureFormats.IA8: return TEX_FORMAT.IA8;
case TextureFormats.RGB565: return TEX_FORMAT.R5G5B5_UNORM;
case TextureFormats.RGB5A3: return TEX_FORMAT.R5G5B5A3_UNORM;
case TextureFormats.RGBA32: return TEX_FORMAT.R32G32B32A32_FLOAT;
case TextureFormats.RGB565: return TEX_FORMAT.RGB565;
case TextureFormats.RGB5A3: return TEX_FORMAT.RGB5A3;
case TextureFormats.RGBA32: return TEX_FORMAT.RGBA32;
default:
throw new Exception("Unknown Format " + Format);
}
@ -72,9 +72,9 @@ namespace Toolbox.Library
case TEX_FORMAT.I8: return TextureFormats.I8;
case TEX_FORMAT.IA4: return TextureFormats.IA4;
case TEX_FORMAT.IA8: return TextureFormats.IA8;
case TEX_FORMAT.R5G5B5_UNORM: return TextureFormats.RGB565;
case TEX_FORMAT.R5G5B5A3_UNORM: return TextureFormats.RGB5A3;
case TEX_FORMAT.R32G32B32A32_FLOAT: return TextureFormats.RGBA32;
case TEX_FORMAT.RGB565: return TextureFormats.RGB565;
case TEX_FORMAT.RGB5A3: return TextureFormats.RGB5A3;
case TEX_FORMAT.RGBA32: return TextureFormats.RGBA32;
default:
throw new Exception("Unknown Format " + Format);
}

View file

@ -98,6 +98,7 @@
<HintPath>..\Toolbox\Lib\NAudio.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<Reference Include="ObjectListView">
<HintPath>..\Toolbox\Lib\ObjectListView.dll</HintPath>
<Private>False</Private>

View file

@ -1 +1 @@
747948e0929dd8935549f97d0e91eb2d59336ea8
2dd7d0617dba111aa487a7da42ed4f5f18627a3f