using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Drawing; using System.Linq; using Toolbox; using System.Windows.Forms; using Toolbox.Library; using Toolbox.Library.IO; using Toolbox.Library.Forms; using Syroot.NintenTools.NSW.Bntx.GFX; namespace FirstPlugin { public class XTX : TreeNodeFile, IFileFormat, IContextMenuNode, ITextureContainer { public FileType FileType { get; set; } = FileType.Image; public bool CanSave { get; set; } public string[] Description { get; set; } = new string[] { "XTX" }; public string[] Extension { get; set; } = new string[] { "*.xtx", "*.z" }; public string FileName { get; set; } public string FilePath { get; set; } public IFileInfo IFileInfo { get; set; } public bool Identify(Stream stream) { using (var reader = new FileReader(stream, true)) { return reader.CheckSignature(4, "DFvN"); } } public bool DisplayIcons => false; //Astc decoding is slow and the UI has loading issues atm public List TextureList { get { List textures = new List(); foreach (STGenericTexture node in Nodes) textures.Add(node); return textures; } set { } } public Type[] Types { get { List types = new List(); return types.ToArray(); } } public void Load(System.IO.Stream stream) { CanSave = true; Text = FileName; LoadFile(stream); for (int i = 0; i < TextureInfos.Count; i++) { string name = Path.GetFileNameWithoutExtension(FileName); TextureInfos[i].Text = TextureInfos.Count == 1 ? name : $"{name}_image{i}"; } } public ToolStripItem[] GetContextMenuItems() { return new ToolStripItem[] { new ToolStripMenuItem("Save", null, Save, Keys.Control | Keys.S), new ToolStripMenuItem("Export All", null, ExportAllAction, Keys.Control | Keys.E), }; } private void Save(object sender, EventArgs args) { SaveFileDialog sfd = new SaveFileDialog(); sfd.DefaultExt = "xtx"; sfd.Filter = "Supported Formats|*.xtx;"; sfd.FileName = FileName; if (sfd.ShowDialog() == DialogResult.OK) { STFileSaver.SaveFileFormat(this, sfd.FileName); } } protected void ExportAllAction(object sender, EventArgs e) { if (Nodes.Count <= 0) return; string formats = FileFilters.XTX; string[] forms = formats.Split('|'); List Formats = new List(); for (int i = 0; i < forms.Length; i++) { if (i > 1 || i == (forms.Length - 1)) //Skip lines with all extensions { if (!forms[i].StartsWith("*")) Formats.Add(forms[i]); } } FolderSelectDialog sfd = new FolderSelectDialog(); if (sfd.ShowDialog() == DialogResult.OK) { string folderPath = sfd.SelectedPath; BatchFormatExport form = new BatchFormatExport(Formats); if (form.ShowDialog() == DialogResult.OK) { string extension = form.GetSelectedExtension(); extension.Replace(" ", string.Empty); foreach (STGenericTexture node in Nodes) { ((STGenericTexture)node).Export($"{folderPath}\\{node.Text}{extension}"); } } } } public void Unload() { } public override void OnAfterAdded() { if (Nodes.Count > 0 && this.TreeView != null) this.TreeView.SelectedNode = Nodes[0]; } public void Save(System.IO.Stream stream) { SaveFile(new FileWriter(stream, true)); } public enum XTXImageFormat : uint { NVN_FORMAT_RGBA8 = 0x00000025, NVN_FORMAT_RGBA8_SRGB = 0x00000038, NVN_FORMAT_RGB10A2 = 0x0000003d, NVN_FORMAT_RGB565 = 0x0000003c, NVN_FORMAT_RGB5A1 = 0x0000003b, NVN_FORMAT_RGBA4 = 0x00000039, NVN_FORMAT_R8 = 0x00000001, NVN_FORMAT_RG8 = 0x0000000d, DXT1 = 0x00000042, DXT3 = 0x00000043, DXT5 = 0x00000044, BC4U = 0x00000049, BC4S = 0x0000004a, BC5U = 0x0000004b, BC5S = 0x0000004c, BC6U = 0x00000050, BC7U = 0x0000004d, BGRA8 = 0x0000006d, //Same order as this https://github.com/aboood40091/BNTX-Editor/blob/master/globals.py //However SRGB goes after unorm ASTC_4x4_UNORM = 0x00000079, ASTC_5x4_UNORM = 0x0000007A, ASTC_5x5_UNORM = 0x0000007B, ASTC_6x5_UNORM = 0x0000007C, ASTC_6x6_UNORM = 0x0000007D, ASTC_8x5_UNORM = 0x0000007E, ASTC_8x6_UNORM = 0x0000007F, ASTC_8x8_UNORM = 0x00000080, ASTC_10x5_UNORM = 0x00000081, ASTC_10x6_UNORM = 0x00000082, ASTC_10x8_UNORM = 0x00000083, ASTC_10x10_UNORM = 0x00000084, ASTC_12x10_UNORM = 0x00000085, ASTC_12x12_UNORM = 0x00000086, ASTC_4x4_SRGB = 0x00000087, ASTC_5x4_SRGB = 0x00000088, ASTC_5x5_SRGB = 0x00000089, ASTC_6x5_SRGB = 0x0000008A, ASTC_6x6_SRGB = 0x0000008B, ASTC_8x5_SRGB = 0x0000008C, ASTC_8x6_SRGB = 0x0000008D, ASTC_8x8_SRGB = 0x0000008E, ASTC_10x5_SRGB = 0x0000008F, ASTC_10x6_SRGB = 0x00000090, ASTC_10x8_SRGB = 0x00000091, ASTC_10x10_SRGB = 0x00000092, ASTC_12x10_SRGB = 0x00000093, ASTC_12x12_SRGB = 0x00000094, }; public uint HeaderSize { get; set; } public uint MajorVersion { get; set; } public uint MinorVersion { get; set; } public List Blocks { get; set; } public List TextureInfos { get; set; } public List TextureBlocks { get; set; } private const int texHeadBlkType = 2; private const int dataBlkType = 3; public void LoadFile(Stream data) { Blocks = new List(); TextureInfos = new List(); TextureBlocks = new List(); FileReader reader = new FileReader(data); string Signature = reader.ReadString(4, Encoding.ASCII); if (Signature != "DFvN") throw new Exception($"Invalid signature {Signature}! Expected DFvN."); HeaderSize = reader.ReadUInt32(); MajorVersion = reader.ReadUInt32(); MinorVersion = reader.ReadUInt32(); uint TextureBlockType = 2; uint DataBlockType = 3; reader.Seek(HeaderSize, SeekOrigin.Begin); bool blockB = false; bool blockC = false; uint ImageInfo = 0; uint images = 0; while (reader.Position < reader.BaseStream.Length) { BlockHeader blockHeader = new BlockHeader(); blockHeader.Read(reader); Blocks.Add(blockHeader); if ((uint)blockHeader.BlockType == TextureBlockType) { ImageInfo += 1; blockB = true; TextureInfo textureInfo = new TextureInfo(); textureInfo.Read(new FileReader(blockHeader.Data)); textureInfo.Text = "Texture " + ImageInfo; TextureInfos.Add(textureInfo); } if ((uint)blockHeader.BlockType == DataBlockType) { images += 1; blockC = true; TextureBlocks.Add(blockHeader.Data); } } int curTex = 0; foreach (var tex in TextureInfos) { tex.ImageData = TextureBlocks[curTex++]; Nodes.Add(tex); } } public void SaveFile(FileWriter writer) { int Alignment = 512; uint TextureInfoType = 2; uint TextureBlockType = 3; SetupBlockSaving(TextureBlockType); writer.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian; writer.WriteSignature("DFvN"); writer.Write(HeaderSize); writer.Write(MajorVersion); writer.Write(MinorVersion); writer.Seek(HeaderSize, SeekOrigin.Begin); int curTexBlock = 0; int curTexImage = 0; foreach (var block in Blocks) { if (block.BlockType == TextureBlockType) { block.Data = TextureInfos[curTexImage].ImageData; block.WriteHeader(writer); block.WriteBlock(writer, 512); curTexImage++; } else if (block.BlockType == TextureInfoType) { block.Data = TextureInfos[curTexImage].Write(); block.WriteHeader(writer); block.WriteBlock(writer); } else { block.WriteHeader(writer); block.WriteBlock(writer); } } writer.Close(); writer.Dispose(); } private void SetupBlockSaving(uint TextureBlockType) { int curTex = 0; foreach (var block in Blocks) { if (block.BlockType == TextureBlockType) { block.Data = TextureInfos[curTex].ImageData; } } } public class BlockHeader { public uint BlockSize { get; set; } public UInt64 DataSize { get; set; } public uint BlockType { get; set; } public uint GlobalBlockIndex { get; set; } public uint IncBlockTypeIndex { get; set; } public long DataOffset; public byte[] Data; public void Read(FileReader reader) { var pos = reader.Position; string Signature = reader.ReadString(4, Encoding.ASCII); if (Signature != "HBvN") throw new Exception($"Invalid signature {Signature}! Expected HBvN."); BlockSize = reader.ReadUInt32(); DataSize = reader.ReadUInt64(); DataOffset = reader.ReadInt64(); BlockType = reader.ReadUInt32(); GlobalBlockIndex = reader.ReadUInt32(); IncBlockTypeIndex = reader.ReadUInt32(); reader.Seek((int)pos + DataOffset, SeekOrigin.Begin); Data = reader.ReadBytes((int)DataSize); } private long headerPos = 0; public void WriteHeader(FileWriter writer) { headerPos = writer.Position; writer.WriteSignature("HBvN"); writer.Write(BlockSize); writer.Write((ulong)Data.Length); writer.Write((ulong)DataOffset); writer.Write(BlockType); writer.Write(GlobalBlockIndex); writer.Write(IncBlockTypeIndex); } public void WriteBlock(FileWriter writer, int DataAlignment = 0) { //From the block size goto where the data will start writer.Seek((int)(BlockSize + headerPos), SeekOrigin.Begin); //Add alignment if necessary if (DataAlignment != 0) writer.Align(DataAlignment); var blockPos = writer.Position; //Satisfy the offset using (writer.TemporarySeek(headerPos + 16, SeekOrigin.Begin)) { //Offset starts from the block header writer.Write(blockPos - headerPos); } writer.Write(Data); //Set the total size uint TotalDataSize =(uint)(writer.Position - blockPos); using (writer.TemporarySeek(headerPos + 8, SeekOrigin.Begin)) { writer.Write((ulong)TotalDataSize); } } } public class TextureInfo : STGenericTexture { public override TEX_FORMAT[] SupportedFormats { get { return new TEX_FORMAT[] { TEX_FORMAT.BC1_UNORM, TEX_FORMAT.BC2_UNORM, TEX_FORMAT.BC3_UNORM, TEX_FORMAT.BC4_UNORM, TEX_FORMAT.BC5_UNORM, TEX_FORMAT.R8_UNORM, TEX_FORMAT.R8G8_UNORM, TEX_FORMAT.R8G8_UNORM, TEX_FORMAT.R10G10B10A2_UNORM, TEX_FORMAT.B5G6R5_UNORM, TEX_FORMAT.B5G5R5A1_UNORM, TEX_FORMAT.B4G4R4A4_UNORM, TEX_FORMAT.R8G8B8A8_UNORM, TEX_FORMAT.R8G8B8A8_UNORM_SRGB, }; } } public override bool CanEdit { get; set; } = true; public UInt64 DataSize { get; set; } public uint Alignment { get; set; } public uint Target { get; set; } public XTXImageFormat XTXFormat { get; set; } public uint SliceSize { get; set; } public uint[] MipOffsets { get; set; } public byte[] ImageData; public uint TextureLayout1; public uint TextureLayout2; public uint BlockHeightLog2; public uint Boolean; public override string ExportFilter => FileFilters.XTX; public override string ReplaceFilter => FileFilters.XTX; public TextureInfo() { CanExport = true; CanReplace = true; } public void Read(FileReader reader) { DataSize = reader.ReadUInt64(); Alignment = reader.ReadUInt32(); Width = reader.ReadUInt32(); Height = reader.ReadUInt32(); Depth = reader.ReadUInt32(); Target = reader.ReadUInt32(); XTXFormat = reader.ReadEnum(true); MipCount = reader.ReadUInt32(); SliceSize = reader.ReadUInt32(); MipOffsets = reader.ReadUInt32s(17); TextureLayout1 = reader.ReadUInt32(); TextureLayout2 = reader.ReadUInt32(); Boolean = reader.ReadUInt32(); BlockHeightLog2 = TextureLayout1 & 7; Format = ConvertFormat(XTXFormat); ArrayCount = (uint)(DataSize / SliceSize); } public byte[] Write() { TextureLayout1 = (uint)BlockHeightLog2; MemoryStream mem = new MemoryStream(); FileWriter writer = new FileWriter(mem); writer.Write((ulong)DataSize); writer.Write(Alignment); writer.Write(Width); writer.Write(Height); writer.Write(Depth); writer.Write(Target); writer.Write(XTXFormat, true); writer.Write(MipCount); writer.Write(SliceSize); writer.Write(MipOffsets); writer.Write(TextureLayout1); writer.Write(TextureLayout2); writer.Write(Boolean); writer.Close(); writer.Dispose(); return mem.ToArray(); } public override void Export(string FileName) { Export(FileName); } public override void Replace(string FileName) { var tex = new TextureData(); tex.Replace(FileName, MipCount, 0, Format); //If it's null, the operation is cancelled if (tex.Texture == null) return; var surfacesNew = tex.GetSurfaces(); var surfaces = GetSurfaces(); ImageData = tex.Texture.TextureData[0][0]; Width = tex.Texture.Width; Height = tex.Texture.Height; MipCount = tex.Texture.MipCount; TextureLayout1 = tex.Texture.textureLayout; TextureLayout2 = tex.Texture.textureLayout2; BlockHeightLog2 = tex.Texture.BlockHeightLog2; Format = tex.Format; XTXFormat = ConvertFromGenericFormat(tex.Format); uint[] mips = TegraX1Swizzle.GenerateMipSizes(tex.Format, tex.Width, tex.Height, tex.Depth, tex.ArrayCount, tex.MipCount)[0]; MipOffsets = new uint[17]; for (int i = 0; i < mips.Length; i++) MipOffsets[i] = mips[i]; surfacesNew.Clear(); surfaces.Clear(); UpdateEditor(); } public override void OnClick(TreeView treeview) { UpdateEditor(); } public void UpdateEditor() { ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase)); if (editor == null) { editor = new ImageEditorBase(); editor.Dock = DockStyle.Fill; LibraryGUI.LoadEditor(editor); } editor.Text = Text; editor.LoadImage(this); editor.LoadProperties(GenericProperties); } public static XTXImageFormat ConvertFromGenericFormat(TEX_FORMAT Format) { switch (Format) { case TEX_FORMAT.BC1_UNORM: return XTXImageFormat.DXT1; case TEX_FORMAT.BC2_UNORM: return XTXImageFormat.DXT3; case TEX_FORMAT.BC3_UNORM: return XTXImageFormat.DXT5; case TEX_FORMAT.BC4_UNORM: return XTXImageFormat.BC4U; case TEX_FORMAT.BC4_SNORM: return XTXImageFormat.BC4S; case TEX_FORMAT.BC5_UNORM: return XTXImageFormat.BC5U; case TEX_FORMAT.BC7_UNORM: return XTXImageFormat.BC7U; case TEX_FORMAT.BC6H_UF16: return XTXImageFormat.BC6U; case TEX_FORMAT.R8_UNORM: return XTXImageFormat.NVN_FORMAT_R8; case TEX_FORMAT.R8G8_UNORM: return XTXImageFormat.NVN_FORMAT_RG8; case TEX_FORMAT.R10G10B10A2_UNORM: return XTXImageFormat.NVN_FORMAT_RGB10A2; case TEX_FORMAT.B5G6R5_UNORM: return XTXImageFormat.NVN_FORMAT_RGB565; case TEX_FORMAT.B5G5R5A1_UNORM: return XTXImageFormat.NVN_FORMAT_RGB5A1; case TEX_FORMAT.B4G4R4A4_UNORM: return XTXImageFormat.NVN_FORMAT_RGBA4; case TEX_FORMAT.R8G8B8A8_UNORM: return XTXImageFormat.NVN_FORMAT_RGBA8; case TEX_FORMAT.R8G8B8A8_UNORM_SRGB: return XTXImageFormat.NVN_FORMAT_RGBA8_SRGB; case TEX_FORMAT.ASTC_4x4_UNORM: return XTXImageFormat.ASTC_4x4_UNORM; case TEX_FORMAT.ASTC_5x4_UNORM: return XTXImageFormat.ASTC_5x4_UNORM; case TEX_FORMAT.ASTC_5x5_UNORM: return XTXImageFormat.ASTC_5x5_UNORM; case TEX_FORMAT.ASTC_6x5_UNORM: return XTXImageFormat.ASTC_6x5_UNORM; case TEX_FORMAT.ASTC_6x6_UNORM: return XTXImageFormat.ASTC_6x6_UNORM; case TEX_FORMAT.ASTC_8x5_UNORM: return XTXImageFormat.ASTC_8x5_UNORM; case TEX_FORMAT.ASTC_8x6_UNORM: return XTXImageFormat.ASTC_8x6_UNORM; case TEX_FORMAT.ASTC_8x8_UNORM: return XTXImageFormat.ASTC_8x8_UNORM; case TEX_FORMAT.ASTC_10x5_UNORM: return XTXImageFormat.ASTC_10x5_UNORM; case TEX_FORMAT.ASTC_10x6_UNORM: return XTXImageFormat.ASTC_10x6_UNORM; case TEX_FORMAT.ASTC_10x10_UNORM: return XTXImageFormat.ASTC_10x10_UNORM; case TEX_FORMAT.ASTC_12x10_UNORM: return XTXImageFormat.ASTC_12x10_UNORM; case TEX_FORMAT.ASTC_12x12_UNORM: return XTXImageFormat.ASTC_12x12_UNORM; case TEX_FORMAT.ASTC_4x4_SRGB: return XTXImageFormat.ASTC_4x4_SRGB; case TEX_FORMAT.ASTC_5x4_SRGB: return XTXImageFormat.ASTC_5x4_SRGB; case TEX_FORMAT.ASTC_5x5_SRGB: return XTXImageFormat.ASTC_5x5_SRGB; case TEX_FORMAT.ASTC_6x5_SRGB: return XTXImageFormat.ASTC_6x5_SRGB; case TEX_FORMAT.ASTC_6x6_SRGB: return XTXImageFormat.ASTC_6x6_SRGB; case TEX_FORMAT.ASTC_8x5_SRGB: return XTXImageFormat.ASTC_8x5_SRGB; case TEX_FORMAT.ASTC_8x6_SRGB: return XTXImageFormat.ASTC_8x6_SRGB; case TEX_FORMAT.ASTC_8x8_SRGB: return XTXImageFormat.ASTC_8x8_SRGB; case TEX_FORMAT.ASTC_10x5_SRGB: return XTXImageFormat.ASTC_10x5_SRGB; case TEX_FORMAT.ASTC_10x6_SRGB: return XTXImageFormat.ASTC_10x6_SRGB; case TEX_FORMAT.ASTC_10x10_SRGB: return XTXImageFormat.ASTC_10x10_SRGB; case TEX_FORMAT.ASTC_12x10_SRGB: return XTXImageFormat.ASTC_12x10_SRGB; case TEX_FORMAT.ASTC_12x12_SRGB: return XTXImageFormat.ASTC_12x12_SRGB; default: throw new Exception($"Cannot convert format {Format}"); } } public static TEX_FORMAT ConvertFormat(uint Format) { return ConvertFormat((XTXImageFormat)Format); } public static TEX_FORMAT ConvertFormat(XTXImageFormat Format) { switch (Format) { case XTXImageFormat.BGRA8: return TEX_FORMAT.B8G8R8A8_UNORM; case XTXImageFormat.DXT1: return TEX_FORMAT.BC1_UNORM; case XTXImageFormat.DXT3: return TEX_FORMAT.BC2_UNORM; case XTXImageFormat.DXT5: return TEX_FORMAT.BC3_UNORM; case XTXImageFormat.BC4U: return TEX_FORMAT.BC4_UNORM; case XTXImageFormat.BC4S: return TEX_FORMAT.BC4_SNORM; case XTXImageFormat.BC5U: return TEX_FORMAT.BC5_UNORM; case XTXImageFormat.BC5S: return TEX_FORMAT.BC5_SNORM; case XTXImageFormat.BC7U: return TEX_FORMAT.BC7_UNORM; case XTXImageFormat.BC6U: return TEX_FORMAT.BC6H_UF16; case XTXImageFormat.NVN_FORMAT_R8: return TEX_FORMAT.R8_UNORM; case XTXImageFormat.NVN_FORMAT_RG8: return TEX_FORMAT.R8G8_UNORM; case XTXImageFormat.NVN_FORMAT_RGB10A2: return TEX_FORMAT.R10G10B10A2_UNORM; case XTXImageFormat.NVN_FORMAT_RGB565: return TEX_FORMAT.B5G6R5_UNORM; case XTXImageFormat.NVN_FORMAT_RGB5A1: return TEX_FORMAT.B5G5R5A1_UNORM; case XTXImageFormat.NVN_FORMAT_RGBA4: return TEX_FORMAT.B4G4R4A4_UNORM; case XTXImageFormat.NVN_FORMAT_RGBA8: return TEX_FORMAT.R8G8B8A8_UNORM; case XTXImageFormat.NVN_FORMAT_RGBA8_SRGB: return TEX_FORMAT.R8G8B8A8_UNORM_SRGB; case XTXImageFormat.ASTC_4x4_UNORM: return TEX_FORMAT.ASTC_4x4_UNORM; case XTXImageFormat.ASTC_5x4_UNORM: return TEX_FORMAT.ASTC_5x4_UNORM; case XTXImageFormat.ASTC_5x5_UNORM: return TEX_FORMAT.ASTC_5x5_UNORM; case XTXImageFormat.ASTC_6x5_UNORM: return TEX_FORMAT.ASTC_6x5_UNORM; case XTXImageFormat.ASTC_6x6_UNORM: return TEX_FORMAT.ASTC_6x6_UNORM; case XTXImageFormat.ASTC_8x5_UNORM: return TEX_FORMAT.ASTC_8x5_UNORM; case XTXImageFormat.ASTC_8x6_UNORM: return TEX_FORMAT.ASTC_8x6_UNORM; case XTXImageFormat.ASTC_8x8_UNORM: return TEX_FORMAT.ASTC_8x8_UNORM; case XTXImageFormat.ASTC_10x5_UNORM: return TEX_FORMAT.ASTC_10x5_UNORM; case XTXImageFormat.ASTC_10x6_UNORM: return TEX_FORMAT.ASTC_10x6_UNORM; case XTXImageFormat.ASTC_10x10_UNORM: return TEX_FORMAT.ASTC_10x10_UNORM; case XTXImageFormat.ASTC_12x10_UNORM: return TEX_FORMAT.ASTC_12x10_UNORM; case XTXImageFormat.ASTC_12x12_UNORM: return TEX_FORMAT.ASTC_12x12_UNORM; case XTXImageFormat.ASTC_4x4_SRGB: return TEX_FORMAT.ASTC_4x4_SRGB; case XTXImageFormat.ASTC_5x4_SRGB: return TEX_FORMAT.ASTC_5x4_SRGB; case XTXImageFormat.ASTC_5x5_SRGB: return TEX_FORMAT.ASTC_5x5_SRGB; case XTXImageFormat.ASTC_6x5_SRGB: return TEX_FORMAT.ASTC_6x5_SRGB; case XTXImageFormat.ASTC_6x6_SRGB: return TEX_FORMAT.ASTC_6x6_SRGB; case XTXImageFormat.ASTC_8x5_SRGB: return TEX_FORMAT.ASTC_8x5_SRGB; case XTXImageFormat.ASTC_8x6_SRGB: return TEX_FORMAT.ASTC_8x6_SRGB; case XTXImageFormat.ASTC_8x8_SRGB: return TEX_FORMAT.ASTC_8x8_SRGB; case XTXImageFormat.ASTC_10x5_SRGB: return TEX_FORMAT.ASTC_10x5_SRGB; case XTXImageFormat.ASTC_10x6_SRGB: return TEX_FORMAT.ASTC_10x6_SRGB; case XTXImageFormat.ASTC_10x10_SRGB: return TEX_FORMAT.ASTC_10x10_SRGB; case XTXImageFormat.ASTC_12x10_SRGB: return TEX_FORMAT.ASTC_12x10_SRGB; case XTXImageFormat.ASTC_12x12_SRGB: return TEX_FORMAT.ASTC_12x12_SRGB; default: throw new Exception($"Cannot convert format {Format}"); } } public override void SetImageData(Bitmap bitmap, int ArrayLevel) { if (bitmap == null) return; //Image is likely disposed and not needed to be applied MipCount = GenerateMipCount(bitmap.Width, bitmap.Height); XTXFormat = ConvertFromGenericFormat(Format); var tex = new Syroot.NintenTools.NSW.Bntx.Texture(); tex.Height = (uint)bitmap.Height; tex.Width = (uint)bitmap.Width; tex.Format = TextureData.GenericToBntxSurfaceFormat(Format); tex.Name = Text; tex.Path = ""; tex.TextureData = new List>(); STChannelType[] channels = SetChannelsByFormat(Format); tex.sparseBinding = 0; //false tex.sparseResidency = 0; //false tex.Flags = 0; tex.Swizzle = 0; tex.textureLayout = 0; tex.Regs = new uint[0]; tex.AccessFlags = AccessFlags.Texture; tex.ArrayLength = (uint)ArrayLevel; tex.MipCount = MipCount; tex.Depth = Depth; tex.Dim = Syroot.NintenTools.NSW.Bntx.GFX.Dim.Dim2D; tex.TileMode = Syroot.NintenTools.NSW.Bntx.GFX.TileMode.Default; tex.textureLayout2 = 0x010007; tex.SurfaceDim = Syroot.NintenTools.NSW.Bntx.GFX.SurfaceDim.Dim2D; tex.SampleCount = 1; tex.Pitch = 32; tex.MipOffsets = new long[tex.MipCount]; var mipmaps = TextureImporterSettings.SwizzleSurfaceMipMaps(tex, GenerateMipsAndCompress(bitmap, MipCount, Format), MipCount); ImageData = Utils.CombineByteArray(mipmaps.ToArray()); } public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0, int DepthLevel = 0) { return TegraX1Swizzle.GetImageData(this, ImageData, ArrayLevel, MipLevel, DepthLevel, BlockHeightLog2, (int)Target); } } } }