From c621554fc7d166c37c0384fa3ed0832e08a25647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Mon, 5 Sep 2022 19:23:13 +0100 Subject: [PATCH 1/5] Initial support for 3DST image files --- .../Nintendo/plugin_nintendo/Images/3dst.cs | 53 +++++++++++++++++++ .../plugin_nintendo/Images/3dstPlugin.cs | 40 ++++++++++++++ .../plugin_nintendo/Images/3dstState.cs | 50 +++++++++++++++++ .../plugin_nintendo/Images/3dstSupport.cs | 51 ++++++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 plugins/Nintendo/plugin_nintendo/Images/3dst.cs create mode 100644 plugins/Nintendo/plugin_nintendo/Images/3dstPlugin.cs create mode 100644 plugins/Nintendo/plugin_nintendo/Images/3dstState.cs create mode 100644 plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs diff --git a/plugins/Nintendo/plugin_nintendo/Images/3dst.cs b/plugins/Nintendo/plugin_nintendo/Images/3dst.cs new file mode 100644 index 00000000..13b46781 --- /dev/null +++ b/plugins/Nintendo/plugin_nintendo/Images/3dst.cs @@ -0,0 +1,53 @@ +using System.Drawing; +using System.IO; +using Kanvas.Swizzle; +using Komponent.IO; +using Kontract.Models.Image; + +namespace plugin_nintendo.Images +{ + class _3dst + { + private static readonly int HeaderSize = Tools.MeasureType(typeof(_3dstHeader)); + + private _3dstHeader _header; + + public ImageInfo Load(Stream input) + { + using var br = new BinaryReaderX(input); + + // Read header + _header = br.ReadType<_3dstHeader>(); + + // Read image data + var imgData = br.ReadBytes((int)(input.Length - 0x80)); + + // Create image info + var imageInfo = new ImageInfo(imgData, _header.format, new Size(_header.width, _header.height)); + imageInfo.RemapPixels.With(context => new CtrSwizzle(context)); + + return imageInfo; + } + + public void Save(Stream output, ImageInfo imageInfo) + { + using var bw = new BinaryWriterX(output); + + // Calculate offsets + var dataOffset = 0x80; + + // Write image data + output.Position = dataOffset; + bw.Write(imageInfo.ImageData); + + // Update header + _header.format = (short)imageInfo.ImageFormat; + _header.width = (short)imageInfo.ImageSize.Width; + _header.height = (short)imageInfo.ImageSize.Height; + + // Write header + output.Position = 0; + bw.WriteType(_header); + } + } +} diff --git a/plugins/Nintendo/plugin_nintendo/Images/3dstPlugin.cs b/plugins/Nintendo/plugin_nintendo/Images/3dstPlugin.cs new file mode 100644 index 00000000..270e935e --- /dev/null +++ b/plugins/Nintendo/plugin_nintendo/Images/3dstPlugin.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading.Tasks; +using Komponent.IO; +using Kontract.Interfaces.FileSystem; +using Kontract.Interfaces.Managers; +using Kontract.Interfaces.Plugins.Identifier; +using Kontract.Interfaces.Plugins.State; +using Kontract.Models; +using Kontract.Models.Context; +using Kontract.Models.IO; + +namespace plugin_nintendo.Images +{ + public class _3dstPlugin : IFilePlugin, IIdentifyFiles + { + public Guid PluginId => Guid.Parse("1fa3a56c-864c-4618-9dfc-22734b91d4c5"); + public PluginType PluginType => PluginType.Image; + public string[] FileExtensions => new[] { "*.3dst" }; + public PluginMetadata Metadata { get; } + + public _3dstPlugin() + { + Metadata = new PluginMetadata("3DST", "DaniElectra", "The image format used for textures and thumbnails on Nintendo Anime Channel."); + } + + public async Task IdentifyAsync(IFileSystem fileSystem, UPath filePath, IdentifyContext identifyContext) + { + var fileStream = await fileSystem.OpenFileAsync(filePath); + + using var br = new BinaryReaderX(fileStream); + var magic = br.ReadString(7); + return magic == "texture"; + } + + public IPluginState CreatePluginState(IBaseFileManager fileManager) + { + return new _3dstState(); + } + } +} diff --git a/plugins/Nintendo/plugin_nintendo/Images/3dstState.cs b/plugins/Nintendo/plugin_nintendo/Images/3dstState.cs new file mode 100644 index 00000000..932ee546 --- /dev/null +++ b/plugins/Nintendo/plugin_nintendo/Images/3dstState.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Kanvas; +using Kontract.Interfaces.FileSystem; +using Kontract.Interfaces.Plugins.State; +using Kontract.Kanvas; +using Kontract.Models.Context; +using Kontract.Models.Image; +using Kontract.Models.IO; + +namespace plugin_nintendo.Images +{ + class _3dstState : IImageState, ILoadFiles, ISaveFiles + { + private _3dst _3dst; + + public EncodingDefinition EncodingDefinition { get; } + public IList Images { get; private set; } + + public bool ContentChanged => IsContentChanged(); + + public _3dstState() + { + _3dst = new _3dst(); + + EncodingDefinition = _3dstSupport.GetEncodingDefinition(); + } + + public async Task Load(IFileSystem fileSystem, UPath filePath, LoadContext loadContext) + { + var fileStream = await fileSystem.OpenFileAsync(filePath); + Images = new List { new KanvasImage(EncodingDefinition, _3dst.Load(fileStream)) }; + } + + public Task Save(IFileSystem fileSystem, UPath savePath, SaveContext saveContext) + { + var fileStream = fileSystem.OpenFile(savePath, FileMode.Create, FileAccess.Write); + _3dst.Save(fileStream, Images[0].ImageInfo); + + return Task.CompletedTask; + } + + private bool IsContentChanged() + { + return Images.Any(x => x.ContentChanged); + } + } +} diff --git a/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs b/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs new file mode 100644 index 00000000..85d1c91a --- /dev/null +++ b/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using Kanvas; +using Komponent.IO.Attributes; +using Kontract.Kanvas; +using Kontract.Models.Image; + +namespace plugin_nintendo.Images +{ + class _3dstHeader + { + [FixedLength(7)] + public string magic; + public int zero1; + public int zero2; + public byte zero3; + public short width; + public short height; + public short format; + } + + class _3dstSupport + { + private static readonly IDictionary Formats = new Dictionary + { + // [0] = ImageFormats.Rgba8888(), + // [1] = ImageFormats.Rgb888(), + // [2] = ImageFormats.Rgba5551(), + // [3] = ImageFormats.Rgb565(), + // [4] = ImageFormats.Rgba4444(), + // [5] = ImageFormats.La88(), + // [6] = ImageFormats.Rg88(), + // [7] = ImageFormats.L8(), + // [8] = ImageFormats.A8(), + // [9] = ImageFormats.La44(), + // [10] = ImageFormats.L4(), + // [11] = ImageFormats.A4(), + // [12] = ImageFormats.Etc1(true), + // [13] = ImageFormats.Etc1A4(true), + [0] = ImageFormats.Rgba8888(), + [4] = ImageFormats.Etc1(true), + }; + + public static EncodingDefinition GetEncodingDefinition() + { + var definition = new EncodingDefinition(); + definition.AddColorEncodings(Formats); + + return definition; + } + } +} From 31588d4552d9616556685ca4862d101c29d51922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Mon, 5 Sep 2022 23:13:59 +0100 Subject: [PATCH 2/5] Fix incorrect read offset Now, we can read and write 3DST (Nintendo Anime Channel) images properly! --- plugins/Nintendo/plugin_nintendo/Images/3dst.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/Nintendo/plugin_nintendo/Images/3dst.cs b/plugins/Nintendo/plugin_nintendo/Images/3dst.cs index 13b46781..68925977 100644 --- a/plugins/Nintendo/plugin_nintendo/Images/3dst.cs +++ b/plugins/Nintendo/plugin_nintendo/Images/3dst.cs @@ -20,6 +20,7 @@ public ImageInfo Load(Stream input) _header = br.ReadType<_3dstHeader>(); // Read image data + br.BaseStream.Position = 0x80; var imgData = br.ReadBytes((int)(input.Length - 0x80)); // Create image info From ba85be33402f94c7b7f83e82c7dd5343165deaab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Tue, 6 Sep 2022 23:53:52 +0100 Subject: [PATCH 3/5] Add RGB888 support to 3DST --- plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs b/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs index 85d1c91a..ab12f1b8 100644 --- a/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs +++ b/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs @@ -22,11 +22,11 @@ class _3dstSupport { private static readonly IDictionary Formats = new Dictionary { - // [0] = ImageFormats.Rgba8888(), - // [1] = ImageFormats.Rgb888(), + [0] = ImageFormats.Rgba8888(), + [1] = ImageFormats.Rgb888(), // [2] = ImageFormats.Rgba5551(), // [3] = ImageFormats.Rgb565(), - // [4] = ImageFormats.Rgba4444(), + [4] = ImageFormats.Etc1(true), // [5] = ImageFormats.La88(), // [6] = ImageFormats.Rg88(), // [7] = ImageFormats.L8(), @@ -34,10 +34,8 @@ class _3dstSupport // [9] = ImageFormats.La44(), // [10] = ImageFormats.L4(), // [11] = ImageFormats.A4(), - // [12] = ImageFormats.Etc1(true), + // [12] = ImageFormats.Rgba4444(), // [13] = ImageFormats.Etc1A4(true), - [0] = ImageFormats.Rgba8888(), - [4] = ImageFormats.Etc1(true), }; public static EncodingDefinition GetEncodingDefinition() From 1356f34a2a70db6a92d453adc44dcbfd44506f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Wed, 7 Sep 2022 15:19:16 +0100 Subject: [PATCH 4/5] Add support for more formats to 3DST --- .../Nintendo/plugin_nintendo/Images/3dstSupport.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs b/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs index ab12f1b8..6b5b9ece 100644 --- a/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs +++ b/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs @@ -24,17 +24,17 @@ class _3dstSupport { [0] = ImageFormats.Rgba8888(), [1] = ImageFormats.Rgb888(), - // [2] = ImageFormats.Rgba5551(), - // [3] = ImageFormats.Rgb565(), + // [2] = ImageFormats.La88(), + // [3] = ImageFormats.Rg88(), [4] = ImageFormats.Etc1(true), - // [5] = ImageFormats.La88(), - // [6] = ImageFormats.Rg88(), - // [7] = ImageFormats.L8(), + [5] = ImageFormats.Rgba5551(), + [6] = ImageFormats.Rgb565(), + [7] = ImageFormats.Rgba4444(), // [8] = ImageFormats.A8(), // [9] = ImageFormats.La44(), // [10] = ImageFormats.L4(), // [11] = ImageFormats.A4(), - // [12] = ImageFormats.Rgba4444(), + // [12] = ImageFormats.L8(), // [13] = ImageFormats.Etc1A4(true), }; From 10128f3e4a76050c4ffac8336cc99618b1377de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Wed, 7 Sep 2022 16:28:12 +0100 Subject: [PATCH 5/5] Add support for A8 format to 3DST This should be the last format remaining to support, as trying to implement any other format will not be rendered by the Nintendo Anime Channel application. --- .../Nintendo/plugin_nintendo/Images/3dstSupport.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs b/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs index 6b5b9ece..3f243300 100644 --- a/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs +++ b/plugins/Nintendo/plugin_nintendo/Images/3dstSupport.cs @@ -24,18 +24,11 @@ class _3dstSupport { [0] = ImageFormats.Rgba8888(), [1] = ImageFormats.Rgb888(), - // [2] = ImageFormats.La88(), - // [3] = ImageFormats.Rg88(), + [2] = ImageFormats.A8(), [4] = ImageFormats.Etc1(true), [5] = ImageFormats.Rgba5551(), [6] = ImageFormats.Rgb565(), - [7] = ImageFormats.Rgba4444(), - // [8] = ImageFormats.A8(), - // [9] = ImageFormats.La44(), - // [10] = ImageFormats.L4(), - // [11] = ImageFormats.A4(), - // [12] = ImageFormats.L8(), - // [13] = ImageFormats.Etc1A4(true), + [7] = ImageFormats.Rgba4444() }; public static EncodingDefinition GetEncodingDefinition()