From e26e2c1dc2efc4c70b03fbc3e4fe163dd7c166e8 Mon Sep 17 00:00:00 2001 From: Thomas Casson Date: Sat, 20 Jan 2024 18:44:51 +0000 Subject: [PATCH 1/3] Add ClutFormat to IImageRead and remove IImage --- OpenKh.Bbs/FontsArc.cs | 5 +- .../Utils/QuantizerFactory.cs | 3 + .../Utils/SpriteImageUtil.cs | 2 + OpenKh.Imaging/IImage.cs | 11 - OpenKh.Imaging/IImageRead.cs | 10 +- OpenKh.Imaging/PngImage.cs | 12 +- OpenKh.Kh2/Imgd.cs | 598 +++++++++--------- OpenKh.Kh2/ModelTexture.cs | 566 ++++++++--------- OpenKh.Kh2/RawBitmap.cs | 2 + .../ImageReadExtensionsTests.cs | 7 + OpenKh.Tests/Imaging/ImageDecodeTests.cs | 1 + OpenKh.Tests/Imaging/ImageExtensionsTests.cs | 4 + OpenKh.Tests/Imaging/PngTests.cs | 4 + OpenKh.Tests/kh2/FontContextTests.cs | 4 +- OpenKh.Tests/kh2/ImageReadExtensionsTests.cs | 4 +- OpenKh.Tools.Common/Imaging/GdiImage.cs | 2 + 16 files changed, 636 insertions(+), 599 deletions(-) delete mode 100644 OpenKh.Imaging/IImage.cs diff --git a/OpenKh.Bbs/FontsArc.cs b/OpenKh.Bbs/FontsArc.cs index 06dee6864..0f6ac9fd1 100644 --- a/OpenKh.Bbs/FontsArc.cs +++ b/OpenKh.Bbs/FontsArc.cs @@ -1,4 +1,4 @@ -using OpenKh.Common; +using OpenKh.Common; using OpenKh.Imaging; using System; using System.Collections.Generic; @@ -20,6 +20,7 @@ internal Image(string name, Arc.Entry mtx, byte[] clut, int width, int maxHeight Name = name; Size = new Size(width, maxHeight); PixelFormat = pixelFormat; + ClutFormat = PixelFormat.Rgba8888; var bpp = 0; switch (pixelFormat) @@ -48,6 +49,8 @@ internal Image(string name, Arc.Entry mtx, byte[] clut, int width, int maxHeight public PixelFormat PixelFormat { get; } + public PixelFormat ClutFormat { get; } + public byte[] GetClut() => _clutData; public byte[] GetData() => _imageData; diff --git a/OpenKh.Command.ImgTool/Utils/QuantizerFactory.cs b/OpenKh.Command.ImgTool/Utils/QuantizerFactory.cs index a4655296d..8a6858f77 100644 --- a/OpenKh.Command.ImgTool/Utils/QuantizerFactory.cs +++ b/OpenKh.Command.ImgTool/Utils/QuantizerFactory.cs @@ -101,6 +101,7 @@ private class LocalImager : IImageRead { public Size Size { get; set; } public PixelFormat PixelFormat { get; set; } + public PixelFormat ClutFormat { get; set; } internal byte[] Clut { get; set; } internal byte[] Data { get; set; } @@ -119,6 +120,7 @@ private static IImageRead ConvertFrom(BitmapOutput output) { Size = size, PixelFormat = PixelFormat.Indexed4, + ClutFormat = PixelFormat.Rgba8888, Clut = ConvertClutFrom(output.Palette), Data = ConvertDataFrom(output.PixelLines, (output.Width + 1) / 2, output.Height), }; @@ -127,6 +129,7 @@ private static IImageRead ConvertFrom(BitmapOutput output) { Size = size, PixelFormat = PixelFormat.Indexed8, + ClutFormat = PixelFormat.Rgba8888, Clut = ConvertClutFrom(output.Palette), Data = ConvertDataFrom(output.PixelLines, output.Width, output.Height), }; diff --git a/OpenKh.Command.TexFooter/Utils/SpriteImageUtil.cs b/OpenKh.Command.TexFooter/Utils/SpriteImageUtil.cs index de08e32e9..a0d4eba80 100644 --- a/OpenKh.Command.TexFooter/Utils/SpriteImageUtil.cs +++ b/OpenKh.Command.TexFooter/Utils/SpriteImageUtil.cs @@ -62,6 +62,7 @@ byte[] SpriteImage { Size = new Size(SpriteWidth, SpriteHeight * NumSpritesInImageData), PixelFormat = pixFmt, + ClutFormat = PixelFormat.Rgba8888, Clut = palette, Data = bitmapData, }; @@ -71,6 +72,7 @@ private class LocalBitmap : IImageRead { public Size Size { get; internal set; } public PixelFormat PixelFormat { get; internal set; } + public PixelFormat ClutFormat { get; internal set; } internal byte[] Clut { get; set; } internal byte[] Data { get; set; } diff --git a/OpenKh.Imaging/IImage.cs b/OpenKh.Imaging/IImage.cs deleted file mode 100644 index 1d20f2d45..000000000 --- a/OpenKh.Imaging/IImage.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Drawing; - -namespace OpenKh.Imaging -{ - public interface IImage - { - Size Size { get; } - - PixelFormat PixelFormat { get; } - } -} diff --git a/OpenKh.Imaging/IImageRead.cs b/OpenKh.Imaging/IImageRead.cs index 7e5f9f0dc..392dc522b 100644 --- a/OpenKh.Imaging/IImageRead.cs +++ b/OpenKh.Imaging/IImageRead.cs @@ -1,7 +1,15 @@ +using System.Drawing; + namespace OpenKh.Imaging { - public interface IImageRead : IImage + public interface IImageRead { + Size Size { get; } + + PixelFormat PixelFormat { get; } + + PixelFormat ClutFormat { get; } + /// /// Get pixels /// diff --git a/OpenKh.Imaging/PngImage.cs b/OpenKh.Imaging/PngImage.cs index 9143a8477..33d1fcbdb 100644 --- a/OpenKh.Imaging/PngImage.cs +++ b/OpenKh.Imaging/PngImage.cs @@ -150,6 +150,7 @@ public PngImage(Stream stream) if (bits == 4 && colorType == ColorType.Indexed) { PixelFormat = PixelFormat.Indexed4; + ClutFormat = PixelFormat.Rgba8888; var stride = (1 + Size.Width) / 2; _data = new byte[stride * Size.Height]; for (int y = 0; y < Size.Height; y++) @@ -163,6 +164,7 @@ public PngImage(Stream stream) else if (bits == 8 && colorType == ColorType.Indexed) { PixelFormat = PixelFormat.Indexed8; + ClutFormat = PixelFormat.Rgba8888; var stride = Size.Width; _data = new byte[stride * Size.Height]; for (int y = 0; y < Size.Height; y++) @@ -176,6 +178,7 @@ public PngImage(Stream stream) else if (bits == 8 && colorType == ColorType.TrueColor) { PixelFormat = PixelFormat.Rgb888; + ClutFormat = PixelFormat.Undefined; var stride = 3 * Size.Width; _data = new byte[stride * Size.Height]; for (int y = 0; y < Size.Height; y++) @@ -204,6 +207,7 @@ public PngImage(Stream stream) else if (bits == 8 && colorType == ColorType.AlphaTrueColor) { PixelFormat = PixelFormat.Rgba8888; + ClutFormat = PixelFormat.Undefined; var stride = 4 * Size.Width; _data = new byte[stride * Size.Height]; for (int y = 0; y < Size.Height; y++) @@ -256,7 +260,7 @@ private void ApplyFilter(byte[] data, int ptr, int pixelSize, int stride, int fi } } else if (filter == 2) - { + { if (ptr != 0) { var endPtr = ptr + stride; @@ -333,7 +337,7 @@ private byte[] PrepareClut(byte[] PLTE, byte[] tRNS, int count) clut[4 * y + 1] = PLTE[3 * y + 1]; clut[4 * y + 2] = PLTE[3 * y + 2]; } - clut[4 * y + 3] = 255; + clut[4 * y + 3] = 255; if (y + 1 <= tRNS?.Length) { clut[4 * y + 3] = tRNS[y]; @@ -380,10 +384,12 @@ public static bool IsValid(Stream stream) public Size Size { get; internal set; } public PixelFormat PixelFormat { get; internal set; } + + public PixelFormat ClutFormat { get; internal set; } public byte[] GetData() => _data; - public byte[] GetClut() => _clut; + public byte[] GetClut() => _clut; #endregion public void Write(Stream stream) => Write(stream, this); diff --git a/OpenKh.Kh2/Imgd.cs b/OpenKh.Kh2/Imgd.cs index 61a4fb767..44f13b86b 100644 --- a/OpenKh.Kh2/Imgd.cs +++ b/OpenKh.Kh2/Imgd.cs @@ -1,195 +1,197 @@ -using OpenKh.Common; -using OpenKh.Imaging; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using Xe.BinaryMapper; -using Xe.IO; -using static OpenKh.Imaging.Tm2; - -namespace OpenKh.Kh2 -{ +using OpenKh.Common; +using OpenKh.Imaging; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using Xe.BinaryMapper; +using Xe.IO; +using static OpenKh.Imaging.Tm2; + +namespace OpenKh.Kh2 +{ public partial class Imgd : IImageRead - { - private class Header - { - [Data] public uint MagicCode { get; set; } - [Data] public int Version { get; set; } - [Data] public int BitmapOffset { get; set; } - [Data] public int BitmapLength { get; set; } - [Data] public int ClutOffset { get; set; } - [Data] public int ClutLength { get; set; } - [Data] public int Unk18 { get; set; } - [Data] public short Width { get; set; } - [Data] public short Height { get; set; } - [Data] public short PowWidth { get; set; } - [Data] public short PowHeight { get; set; } - [Data] public short WidthDiv64 { get; set; } - [Data] public ushort GsPsm { get; set; } - [Data] public int Unk28 { get; set; } - [Data] public ushort ClutWidth { get; set; } - [Data] public ushort ClutHeight { get; set; } - [Data] public short Unk30 { get; set; } - [Data] public ushort ClutFormat { get; set; } - [Data] public ushort ImageType { get; set; } - [Data] public ushort ClutType { get; set; } - [Data] public int Reserved { get; set; } - [Data] public int Flags { get; set; } + { + private class Header + { + [Data] public uint MagicCode { get; set; } + [Data] public int Version { get; set; } + [Data] public int BitmapOffset { get; set; } + [Data] public int BitmapLength { get; set; } + [Data] public int ClutOffset { get; set; } + [Data] public int ClutLength { get; set; } + [Data] public int Unk18 { get; set; } + [Data] public short Width { get; set; } + [Data] public short Height { get; set; } + [Data] public short PowWidth { get; set; } + [Data] public short PowHeight { get; set; } + [Data] public short WidthDiv64 { get; set; } + [Data] public ushort GsPsm { get; set; } + [Data] public int Unk28 { get; set; } + [Data] public ushort ClutWidth { get; set; } + [Data] public ushort ClutHeight { get; set; } + [Data] public short Unk30 { get; set; } + [Data] public ushort ClutFormat { get; set; } + [Data] public ushort ImageType { get; set; } + [Data] public ushort ClutType { get; set; } + [Data] public int Reserved { get; set; } + [Data] public int Flags { get; set; } + } + + private const uint MagicCode = 0x44474D49U; + private const int HeaderLength = 0x40; + private const int SwizzledFlag = 4; + private const int FacAlignment = 0x800; + private static readonly InvalidDataException InvalidHeaderException = new InvalidDataException("Invalid header"); + + public static bool IsValid(Stream stream) => + stream.Length >= HeaderLength && stream.SetPosition(0).ReadInt32() == MagicCode; + + private readonly GsPSM _format; + private readonly int _flags; + + private Imgd(Stream stream) + { + stream + .MustReadAndSeek() + .MustHaveHeaderLengthOf(HeaderLength); + + var reader = new BinaryReader(stream); + var header = BinaryMapping.ReadObject
(stream); + if (header.MagicCode != MagicCode) + throw InvalidHeaderException; + + Size = new Size(header.Width, header.Height); + _format = (GsPSM)header.GsPsm; + _flags = header.Flags; + + stream.SetPosition(header.BitmapOffset); + var data = reader.ReadBytes(header.BitmapLength); + + // Swap pixel order for only unswizzled 4-bpp IMGD. + Data = (_format == GsPSM.GS_PSMT4 && (_flags & SwizzledFlag) == 0) + ? GetSwappedPixelData(data) + : data; + + stream.SetPosition(header.ClutOffset); + Clut = reader.ReadBytes(header.ClutLength); + } + + public static Imgd Read(Stream stream) => new Imgd(stream.SetPosition(0)); + + public void Write(Stream stream) + { + stream.MustWriteAndSeek(); + + BinaryMapping.WriteObject(stream, new Header + { + MagicCode = MagicCode, + Version = 0x100, + BitmapOffset = HeaderLength, + BitmapLength = Data.Length, + ClutOffset = HeaderLength + Data.Length, + ClutLength = Clut?.Length ?? 0, + Unk18 = -1, + Width = (short)Size.Width, + Height = (short)Size.Height, + PowWidth = GetPow(Size.Width), + PowHeight = GetPow(Size.Height), + WidthDiv64 = (short)(Size.Width / 64), + GsPsm = (ushort)_format, + Unk28 = -1, + ClutWidth = (ushort)(_format == GsPSM.GS_PSMT4 ? 8 : 16), + ClutHeight = (ushort)(_format == GsPSM.GS_PSMT4 ? 2 : 16), + Unk30 = 1, + ClutFormat = (ushort)(_format == GsPSM.GS_PSMCT32 ? (GsCPSM)19: GsCPSM.GS_PSMCT32), + ImageType = (ushort)GetImageType(_format), + ClutType = (ushort)(_format == GsPSM.GS_PSMCT32 ? 0 : CLT_TYPE.CT_ABGR8), + Reserved = 0, + Flags = _flags, + }); + + // Swap pixel order for only unswizzled 4-bpp IMGD. + var data = (_format == GsPSM.GS_PSMT4 && (_flags & SwizzledFlag) == 0) + ? GetSwappedPixelData(Data) + : Data; + + stream.Write(data, 0, data.Length); + + if (Clut != null) + stream.Write(Clut, 0, Clut.Length); + } + + public static bool IsFac(Stream stream) + { + if (stream.Length < HeaderLength) + return false; + + stream.MustReadAndSeek().SetPosition(0); + var header = BinaryMapping.ReadObject
(stream); + if (header.MagicCode != MagicCode) + return false; + + stream + .SetPosition(header.ClutOffset + header.ClutLength) + .AlignPosition(FacAlignment); + + if (stream.Position + HeaderLength >= stream.Length) + return false; + + header = BinaryMapping.ReadObject
(stream); + if (header.MagicCode != MagicCode) + return false; + + return true; + } + + public static IEnumerable ReadAsFac(Stream stream) + { + stream.SetPosition(0); + while (true) + { + stream.AlignPosition(FacAlignment); + var subStreamLength = stream.Length - stream.Position; + if (subStreamLength < HeaderLength) + yield break; + + yield return Imgd.Read(new SubStream(stream, stream.Position, subStreamLength)); + } + } + + public static void WriteAsFac(Stream stream, IEnumerable images) + { + foreach (var image in images) + { + image.Write(stream); + stream.SetLength(stream.AlignPosition(FacAlignment).Position); + } } - private const uint MagicCode = 0x44474D49U; - private const int HeaderLength = 0x40; - private const int SwizzledFlag = 4; - private const int FacAlignment = 0x800; - private static readonly InvalidDataException InvalidHeaderException = new InvalidDataException("Invalid header"); - - public static bool IsValid(Stream stream) => - stream.Length >= HeaderLength && stream.SetPosition(0).ReadInt32() == MagicCode; - - private readonly GsPSM _format; - private readonly int _flags; - - private Imgd(Stream stream) - { - stream - .MustReadAndSeek() - .MustHaveHeaderLengthOf(HeaderLength); - - var reader = new BinaryReader(stream); - var header = BinaryMapping.ReadObject
(stream); - if (header.MagicCode != MagicCode) - throw InvalidHeaderException; - - Size = new Size(header.Width, header.Height); - _format = (GsPSM)header.GsPsm; - _flags = header.Flags; - - stream.SetPosition(header.BitmapOffset); - var data = reader.ReadBytes(header.BitmapLength); - - // Swap pixel order for only unswizzled 4-bpp IMGD. - Data = (_format == GsPSM.GS_PSMT4 && (_flags & SwizzledFlag) == 0) - ? GetSwappedPixelData(data) - : data; - - stream.SetPosition(header.ClutOffset); - Clut = reader.ReadBytes(header.ClutLength); - } - - public static Imgd Read(Stream stream) => new Imgd(stream.SetPosition(0)); - - public void Write(Stream stream) - { - stream.MustWriteAndSeek(); - - BinaryMapping.WriteObject(stream, new Header - { - MagicCode = MagicCode, - Version = 0x100, - BitmapOffset = HeaderLength, - BitmapLength = Data.Length, - ClutOffset = HeaderLength + Data.Length, - ClutLength = Clut?.Length ?? 0, - Unk18 = -1, - Width = (short)Size.Width, - Height = (short)Size.Height, - PowWidth = GetPow(Size.Width), - PowHeight = GetPow(Size.Height), - WidthDiv64 = (short)(Size.Width / 64), - GsPsm = (ushort)_format, - Unk28 = -1, - ClutWidth = (ushort)(_format == GsPSM.GS_PSMT4 ? 8 : 16), - ClutHeight = (ushort)(_format == GsPSM.GS_PSMT4 ? 2 : 16), - Unk30 = 1, - ClutFormat = (ushort)(_format == GsPSM.GS_PSMCT32 ? (GsCPSM)19: GsCPSM.GS_PSMCT32), - ImageType = (ushort)GetImageType(_format), - ClutType = (ushort)(_format == GsPSM.GS_PSMCT32 ? 0 : CLT_TYPE.CT_ABGR8), - Reserved = 0, - Flags = _flags, - }); - - // Swap pixel order for only unswizzled 4-bpp IMGD. - var data = (_format == GsPSM.GS_PSMT4 && (_flags & SwizzledFlag) == 0) - ? GetSwappedPixelData(Data) - : Data; - - stream.Write(data, 0, data.Length); - - if (Clut != null) - stream.Write(Clut, 0, Clut.Length); - } - - public static bool IsFac(Stream stream) - { - if (stream.Length < HeaderLength) - return false; - - stream.MustReadAndSeek().SetPosition(0); - var header = BinaryMapping.ReadObject
(stream); - if (header.MagicCode != MagicCode) - return false; - - stream - .SetPosition(header.ClutOffset + header.ClutLength) - .AlignPosition(FacAlignment); - - if (stream.Position + HeaderLength >= stream.Length) - return false; - - header = BinaryMapping.ReadObject
(stream); - if (header.MagicCode != MagicCode) - return false; - - return true; - } - - public static IEnumerable ReadAsFac(Stream stream) - { - stream.SetPosition(0); - while (true) - { - stream.AlignPosition(FacAlignment); - var subStreamLength = stream.Length - stream.Position; - if (subStreamLength < HeaderLength) - yield break; - - yield return Imgd.Read(new SubStream(stream, stream.Position, subStreamLength)); - } - } - - public static void WriteAsFac(Stream stream, IEnumerable images) - { - foreach (var image in images) - { - image.Write(stream); - stream.SetLength(stream.AlignPosition(FacAlignment).Position); - } - } - - public Size Size { get; } - + public Size Size { get; } + /// /// Raw data affected by IsSwizzled flag. If IsSwizzled is true, it is encoded data. - /// - /// + /// + /// /// Accept pixel order in the following styles for unswizzled data: /// - `Indexed4`: The first pixel is high byte. The second pixel is low byte. /// - `Indexed8`: No conversion, one byte is one pixel. /// - `Rgba8888`: `RR GG BB AA` - /// - public byte[] Data { get; } - + /// + public byte[] Data { get; } + /// /// Represents color look at table in this order: `RR GG BB AA`, for `Indexed4` or `Indexed8` images. /// `AA` uses Ps2 alpha range (0 to 128). - /// - public byte[] Clut { get; } - - public bool IsSwizzled => (_flags & 4) != 0; - - public PixelFormat PixelFormat => GetPixelFormat(_format); - + /// + public byte[] Clut { get; } + + public bool IsSwizzled => (_flags & 4) != 0; + + public PixelFormat PixelFormat => GetPixelFormat(_format); + + public PixelFormat ClutFormat => PixelFormat.Rgba8888; + /// /// Get pixels /// @@ -199,124 +201,124 @@ public static void WriteAsFac(Stream stream, IEnumerable images) /// - `Indexed8`: No conversion, one byte is one pixel. /// - `Rgba8888`: `BB GG RR AA` (same as Format32bppArgb) /// - public byte[] GetData() - { - switch (_format) - { - case GsPSM.GS_PSMCT32: - return GetData32bpp(); - case GsPSM.GS_PSMT8: - return IsSwizzled ? Ps2.Decode8(Ps2.Encode32(Data, Size.Width / 128, Size.Height / 64), Size.Width / 128, Size.Height / 64) : Data; - case GsPSM.GS_PSMT4: - return IsSwizzled ? Ps2.Decode4(Ps2.Encode32(Data, Size.Width / 128, Size.Height / 128), Size.Width / 128, Size.Height / 128) : Data; - default: - throw new NotSupportedException($"The format {_format} is not supported."); - } - } - + public byte[] GetData() + { + switch (_format) + { + case GsPSM.GS_PSMCT32: + return GetData32bpp(); + case GsPSM.GS_PSMT8: + return IsSwizzled ? Ps2.Decode8(Ps2.Encode32(Data, Size.Width / 128, Size.Height / 64), Size.Width / 128, Size.Height / 64) : Data; + case GsPSM.GS_PSMT4: + return IsSwizzled ? Ps2.Decode4(Ps2.Encode32(Data, Size.Width / 128, Size.Height / 128), Size.Width / 128, Size.Height / 128) : Data; + default: + throw new NotSupportedException($"The format {_format} is not supported."); + } + } + /// /// Get color look at table in this order: `RR GG BB AA`, for `Indexed4` or `Indexed8` images. /// `AA` uses normal alpha range (0 to 255). - /// - public byte[] GetClut() - { - switch (_format) - { - case GsPSM.GS_PSMT8: return GetClut8(); - case GsPSM.GS_PSMT4: return GetClut4(); - default: - throw new NotSupportedException($"The format {_format} is not supported or does not contain any palette."); - } - } - - private byte[] GetClut4() - { - var data = new byte[16 * 4]; - for (var i = 0; i < 16; i++) - { - data[i * 4 + 0] = Clut[i * 4 + 0]; - data[i * 4 + 1] = Clut[i * 4 + 1]; - data[i * 4 + 2] = Clut[i * 4 + 2]; - data[i * 4 + 3] = Ps2.FromPs2Alpha(Clut[i * 4 + 3]); - } - - return data; - } - - private byte[] GetClut8() - { - var data = new byte[256 * 4]; - for (var i = 0; i < 256; i++) - { - var srcIndex = Ps2.Repl(i); - if (srcIndex * 4 < Clut.Length) - { - data[i * 4 + 0] = Clut[srcIndex * 4 + 0]; - data[i * 4 + 1] = Clut[srcIndex * 4 + 1]; - data[i * 4 + 2] = Clut[srcIndex * 4 + 2]; - data[i * 4 + 3] = Ps2.FromPs2Alpha(Clut[srcIndex * 4 + 3]); - } - } - - return data; - } - - private byte[] GetData32bpp() - { - var newData = new byte[Data.Length]; - for (var i = 0; i < newData.Length - 3; i += 4) - { - newData[i + 0] = Data[i + 2]; - newData[i + 1] = Data[i + 1]; - newData[i + 2] = Data[i + 0]; - newData[i + 3] = Ps2.FromPs2Alpha(Data[i + 3]); - } - - return newData; - } - - private static short GetPow(int value) - { - short pow = 1; - while (value > (1 << pow)) - pow++; - - return pow; - } - - private static PixelFormat GetPixelFormat(GsPSM format) - { - switch (format) - { - case GsPSM.GS_PSMCT32: return PixelFormat.Rgba8888; - case GsPSM.GS_PSMT8: return PixelFormat.Indexed8; - case GsPSM.GS_PSMT4: return PixelFormat.Indexed4; - default: return PixelFormat.Undefined; - } - } - - private static GsPSM GetFormat(PixelFormat pixelFormat) - { - switch (pixelFormat) - { - case PixelFormat.Rgba8888: return GsPSM.GS_PSMCT32; - case PixelFormat.Indexed4: return GsPSM.GS_PSMT4; - case PixelFormat.Indexed8: return GsPSM.GS_PSMT8; - default: - throw new ArgumentOutOfRangeException( - $"Pixel format {pixelFormat} is not supported."); - } - } - - private static IMG_TYPE GetImageType(GsPSM format) - { - return format switch - { - GsPSM.GS_PSMCT32 => IMG_TYPE.IT_RGBA, - GsPSM.GS_PSMT4 => IMG_TYPE.IT_CLUT4, - GsPSM.GS_PSMT8 => IMG_TYPE.IT_CLUT8, - _ => throw new ArgumentOutOfRangeException($"Format {format} is not supported."), - }; - } - } -} + /// + public byte[] GetClut() + { + switch (_format) + { + case GsPSM.GS_PSMT8: return GetClut8(); + case GsPSM.GS_PSMT4: return GetClut4(); + default: + throw new NotSupportedException($"The format {_format} is not supported or does not contain any palette."); + } + } + + private byte[] GetClut4() + { + var data = new byte[16 * 4]; + for (var i = 0; i < 16; i++) + { + data[i * 4 + 0] = Clut[i * 4 + 0]; + data[i * 4 + 1] = Clut[i * 4 + 1]; + data[i * 4 + 2] = Clut[i * 4 + 2]; + data[i * 4 + 3] = Ps2.FromPs2Alpha(Clut[i * 4 + 3]); + } + + return data; + } + + private byte[] GetClut8() + { + var data = new byte[256 * 4]; + for (var i = 0; i < 256; i++) + { + var srcIndex = Ps2.Repl(i); + if (srcIndex * 4 < Clut.Length) + { + data[i * 4 + 0] = Clut[srcIndex * 4 + 0]; + data[i * 4 + 1] = Clut[srcIndex * 4 + 1]; + data[i * 4 + 2] = Clut[srcIndex * 4 + 2]; + data[i * 4 + 3] = Ps2.FromPs2Alpha(Clut[srcIndex * 4 + 3]); + } + } + + return data; + } + + private byte[] GetData32bpp() + { + var newData = new byte[Data.Length]; + for (var i = 0; i < newData.Length - 3; i += 4) + { + newData[i + 0] = Data[i + 2]; + newData[i + 1] = Data[i + 1]; + newData[i + 2] = Data[i + 0]; + newData[i + 3] = Ps2.FromPs2Alpha(Data[i + 3]); + } + + return newData; + } + + private static short GetPow(int value) + { + short pow = 1; + while (value > (1 << pow)) + pow++; + + return pow; + } + + private static PixelFormat GetPixelFormat(GsPSM format) + { + switch (format) + { + case GsPSM.GS_PSMCT32: return PixelFormat.Rgba8888; + case GsPSM.GS_PSMT8: return PixelFormat.Indexed8; + case GsPSM.GS_PSMT4: return PixelFormat.Indexed4; + default: return PixelFormat.Undefined; + } + } + + private static GsPSM GetFormat(PixelFormat pixelFormat) + { + switch (pixelFormat) + { + case PixelFormat.Rgba8888: return GsPSM.GS_PSMCT32; + case PixelFormat.Indexed4: return GsPSM.GS_PSMT4; + case PixelFormat.Indexed8: return GsPSM.GS_PSMT8; + default: + throw new ArgumentOutOfRangeException( + $"Pixel format {pixelFormat} is not supported."); + } + } + + private static IMG_TYPE GetImageType(GsPSM format) + { + return format switch + { + GsPSM.GS_PSMCT32 => IMG_TYPE.IT_RGBA, + GsPSM.GS_PSMT4 => IMG_TYPE.IT_CLUT4, + GsPSM.GS_PSMT8 => IMG_TYPE.IT_CLUT8, + _ => throw new ArgumentOutOfRangeException($"Format {format} is not supported."), + }; + } + } +} diff --git a/OpenKh.Kh2/ModelTexture.cs b/OpenKh.Kh2/ModelTexture.cs index 1ccc3a3a9..f1705db34 100644 --- a/OpenKh.Kh2/ModelTexture.cs +++ b/OpenKh.Kh2/ModelTexture.cs @@ -1,141 +1,143 @@ -using OpenKh.Common; -using OpenKh.Imaging; -using OpenKh.Kh2.TextureFooter; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Linq; +using OpenKh.Common; +using OpenKh.Imaging; +using OpenKh.Kh2.TextureFooter; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; using System.Text; -using Xe.BinaryMapper; - -namespace OpenKh.Kh2 -{ - public class ModelTexture - { - private class Header - { - [Data] public int MagicCode { get; set; } // shorts type + flag - [Data] public int ColorCount { get; set; } // clutDataNum (Color LookUp Table) / Color Palettes - [Data] public int TextureInfoCount { get; set; } // pixelDataNum - [Data] public int GsInfoCount { get; set; } // textureEnvNum - [Data] public int Offset1 { get; set; } // pixelNoOffset - [Data] public int Texinf1off { get; set; } // sendPacketOffset - [Data] public int Texinf2off { get; set; } // textureEnvPacketOffset - [Data] public int PictureOffset { get; set; } // pixelDataOffset - [Data] public int PaletteOffset { get; set; } // clutDataOffset - } - - public class Texture : IImageRead - { - private readonly byte[] _data; - private readonly byte[] _palette; - private readonly int _cbp; - private readonly int _csa; - private readonly Tm2.GsPSM _uploadPixelFormat; - - internal Texture( - int width, int height, PixelFormat pixelFormat, Tm2.GsPSM uploadPixelFormat, - byte[] data, byte[] palette, - TextureAddressMode textureAddressMode, int cbp, int csa) - { - Size = new Size(width, height); - PixelFormat = pixelFormat; - _uploadPixelFormat = uploadPixelFormat; - _data = data; - _palette = palette; - TextureAddressMode = textureAddressMode; - _cbp = cbp; - _csa = csa; - } - - public Size Size { get; } - - public PixelFormat PixelFormat { get; } - - public TextureAddressMode TextureAddressMode { get; } - - public byte[] GetClut() - { - switch (PixelFormat) - { - case PixelFormat.Indexed8: - return GetClut8(_palette, _cbp, _csa); - case PixelFormat.Indexed4: - return GetClut4(_palette, _cbp, _csa); - default: - throw new NotSupportedException($"The format {PixelFormat} is not supported or does not contain any palette."); - } - } - - public byte[] GetData() - { - switch (PixelFormat) - { - case PixelFormat.Rgba8888: - case PixelFormat.Rgbx8888: - return GetData32bpp(_data); - case PixelFormat.Indexed8: - if (_uploadPixelFormat == Tm2.GsPSM.GS_PSMCT32) - return Ps2.Decode8(Ps2.Encode32(_data, Size.Width / 128, Size.Height / 64), Size.Width / 128, Size.Height / 64); - return _data; - case PixelFormat.Indexed4: - if (_uploadPixelFormat == Tm2.GsPSM.GS_PSMCT32) - return Ps2.Decode4(Ps2.Encode32(_data, Size.Width / 128, Size.Height / 128), Size.Width / 128, Size.Height / 128); - return _data; - default: - throw new NotSupportedException($"The format {PixelFormat} is not supported."); - } - } - } - - private class DataTransferInfo +using Xe.BinaryMapper; + +namespace OpenKh.Kh2 +{ + public class ModelTexture + { + private class Header + { + [Data] public int MagicCode { get; set; } // shorts type + flag + [Data] public int ColorCount { get; set; } // clutDataNum (Color LookUp Table) / Color Palettes + [Data] public int TextureInfoCount { get; set; } // pixelDataNum + [Data] public int GsInfoCount { get; set; } // textureEnvNum + [Data] public int Offset1 { get; set; } // pixelNoOffset + [Data] public int Texinf1off { get; set; } // sendPacketOffset + [Data] public int Texinf2off { get; set; } // textureEnvPacketOffset + [Data] public int PictureOffset { get; set; } // pixelDataOffset + [Data] public int PaletteOffset { get; set; } // clutDataOffset + } + + public class Texture : IImageRead + { + private readonly byte[] _data; + private readonly byte[] _palette; + private readonly int _cbp; + private readonly int _csa; + private readonly Tm2.GsPSM _uploadPixelFormat; + + internal Texture( + int width, int height, PixelFormat pixelFormat, Tm2.GsPSM uploadPixelFormat, + byte[] data, byte[] palette, + TextureAddressMode textureAddressMode, int cbp, int csa) + { + Size = new Size(width, height); + PixelFormat = pixelFormat; + _uploadPixelFormat = uploadPixelFormat; + _data = data; + _palette = palette; + TextureAddressMode = textureAddressMode; + _cbp = cbp; + _csa = csa; + } + + public Size Size { get; } + + public PixelFormat PixelFormat { get; } + + public PixelFormat ClutFormat => PixelFormat.Rgba8888; + + public TextureAddressMode TextureAddressMode { get; } + + public byte[] GetClut() + { + switch (PixelFormat) + { + case PixelFormat.Indexed8: + return GetClut8(_palette, _cbp, _csa); + case PixelFormat.Indexed4: + return GetClut4(_palette, _cbp, _csa); + default: + throw new NotSupportedException($"The format {PixelFormat} is not supported or does not contain any palette."); + } + } + + public byte[] GetData() + { + switch (PixelFormat) + { + case PixelFormat.Rgba8888: + case PixelFormat.Rgbx8888: + return GetData32bpp(_data); + case PixelFormat.Indexed8: + if (_uploadPixelFormat == Tm2.GsPSM.GS_PSMCT32) + return Ps2.Decode8(Ps2.Encode32(_data, Size.Width / 128, Size.Height / 64), Size.Width / 128, Size.Height / 64); + return _data; + case PixelFormat.Indexed4: + if (_uploadPixelFormat == Tm2.GsPSM.GS_PSMCT32) + return Ps2.Decode4(Ps2.Encode32(_data, Size.Width / 128, Size.Height / 128), Size.Width / 128, Size.Height / 128); + return _data; + default: + throw new NotSupportedException($"The format {PixelFormat} is not supported."); + } + } + } + + private class DataTransferInfo { public DataTransferInfo() { } - public BITBLTBUF BitBltBuf { get; set; } + public BITBLTBUF BitBltBuf { get; set; } public TRXPOS TrxPos { get; set; } - public TRXREG TrxReg { get; set; } - public TRXDIR TrxDir { get; set; } - public int DataOffset { get; set; } - - public int QuadWordCount { get; set; } - } - - private class _DataTransfer - { - [Data] public int Data00 { get; set; } // giftag0 > Should be 128 bits (16 bytes) - [Data] public int Data04 { get; set; } - [Data] public int Data08 { get; set; } - [Data] public int Data0c { get; set; } - [Data] public int Data10 { get; set; } - [Data] public int Data14 { get; set; } - [Data] public int Data18 { get; set; } - [Data] public int Data1c { get; set; } - [Data] public BITBLTBUF BitBltBuf { get; set; } - [Data] public long GSReg50 { get; set; } // bitbltbuf_addr - [Data] public TRXPOS TrxPos { get; set; } - [Data] public long GSReg51 { get; set; } // trxpos_addr - [Data] public TRXREG TrxReg { get; set; } - [Data] public long GSReg52 { get; set; } // trxreg_addr - [Data] public TRXDIR TrxDir { get; set; } - [Data] public long GSReg53 { get; set; } // trxdir_addr - [Data] public int Data60 { get; set; } // giftag1 > Should be 128 bits (16 bytes) - [Data] public int Data64 { get; set; } - [Data] public int Data68 { get; set; } - [Data] public int Data6c { get; set; } - [Data] public int Data70 { get; set; } - [Data] public int DataOffset { get; set; } - [Data] public int Data78 { get; set; } - [Data] public int Data7c { get; set; } - [Data] public int Data80 { get; set; } - [Data] public int Data84 { get; set; } - [Data] public int Data88 { get; set; } - [Data] public int Data8c { get; set; } - + public TRXREG TrxReg { get; set; } + public TRXDIR TrxDir { get; set; } + public int DataOffset { get; set; } + + public int QuadWordCount { get; set; } + } + + private class _DataTransfer + { + [Data] public int Data00 { get; set; } // giftag0 > Should be 128 bits (16 bytes) + [Data] public int Data04 { get; set; } + [Data] public int Data08 { get; set; } + [Data] public int Data0c { get; set; } + [Data] public int Data10 { get; set; } + [Data] public int Data14 { get; set; } + [Data] public int Data18 { get; set; } + [Data] public int Data1c { get; set; } + [Data] public BITBLTBUF BitBltBuf { get; set; } + [Data] public long GSReg50 { get; set; } // bitbltbuf_addr + [Data] public TRXPOS TrxPos { get; set; } + [Data] public long GSReg51 { get; set; } // trxpos_addr + [Data] public TRXREG TrxReg { get; set; } + [Data] public long GSReg52 { get; set; } // trxreg_addr + [Data] public TRXDIR TrxDir { get; set; } + [Data] public long GSReg53 { get; set; } // trxdir_addr + [Data] public int Data60 { get; set; } // giftag1 > Should be 128 bits (16 bytes) + [Data] public int Data64 { get; set; } + [Data] public int Data68 { get; set; } + [Data] public int Data6c { get; set; } + [Data] public int Data70 { get; set; } + [Data] public int DataOffset { get; set; } + [Data] public int Data78 { get; set; } + [Data] public int Data7c { get; set; } + [Data] public int Data80 { get; set; } + [Data] public int Data84 { get; set; } + [Data] public int Data88 { get; set; } + [Data] public int Data8c { get; set; } + public int QuadWordCount => Data60 & 0x7FFF; public DataTransferInfo ToInfo() => new DataTransferInfo @@ -145,58 +147,58 @@ private class _DataTransfer TrxReg = TrxReg, TrxDir = TrxDir, DataOffset = DataOffset, - QuadWordCount = QuadWordCount, + QuadWordCount = QuadWordCount, }; - } - - public class GsInfo - { - public MIPTBP1 MipTbp1 { get; set; } - public MIPTBP2 MipTbp2 { get; set; } - public Tm2.GsTex Tex2 { get; set; } - public TEX1 Tex1 { get; set; } - public Tm2.GsTex Tex0 { get; set; } - public TextureAddressMode AddressMode { get; set; } - } - - private class _GsInfo - { - [Data] public long Data00 { get; set; } - [Data] public long Data08 { get; set; } - [Data] public long Data10 { get; set; } - [Data] public long Data18 { get; set; } - [Data] public long TexFlush { get; set; } - [Data] public long GSReg3F { get; set; } - [Data] public MIPTBP1 MipTbp1 { get; set; } - [Data] public long GSReg34 { get; set; } - [Data] public MIPTBP2 MipTbp2 { get; set; } - [Data] public long GSReg36 { get; set; } - [Data] public Tm2.GsTex Tex2 { get; set; } - [Data] public long GSReg16 { get; set; } - [Data] public TEX1 Tex1 { get; set; } - [Data] public long GSReg14 { get; set; } - [Data] public Tm2.GsTex Tex0 { get; set; } - [Data] public long GSReg06 { get; set; } - [Data] public CLAMP Clamp { get; set; } - [Data] public long Data88 { get; set; } - [Data] public long Data90 { get; set; } - [Data] public long Data98 { get; set; } - } - - public enum TextureWrapMode - { - Repeat, Clamp, RegionClamp, RegionRepeat - } - - public class TextureAddressMode - { - public TextureWrapMode AddressU { get; set; } - public TextureWrapMode AddressV { get; set; } - public int Left { get; set; } - public int Top { get; set; } - public int Right { get; set; } - public int Bottom { get; set; } + } + + public class GsInfo + { + public MIPTBP1 MipTbp1 { get; set; } + public MIPTBP2 MipTbp2 { get; set; } + public Tm2.GsTex Tex2 { get; set; } + public TEX1 Tex1 { get; set; } + public Tm2.GsTex Tex0 { get; set; } + public TextureAddressMode AddressMode { get; set; } + } + + private class _GsInfo + { + [Data] public long Data00 { get; set; } + [Data] public long Data08 { get; set; } + [Data] public long Data10 { get; set; } + [Data] public long Data18 { get; set; } + [Data] public long TexFlush { get; set; } + [Data] public long GSReg3F { get; set; } + [Data] public MIPTBP1 MipTbp1 { get; set; } + [Data] public long GSReg34 { get; set; } + [Data] public MIPTBP2 MipTbp2 { get; set; } + [Data] public long GSReg36 { get; set; } + [Data] public Tm2.GsTex Tex2 { get; set; } + [Data] public long GSReg16 { get; set; } + [Data] public TEX1 Tex1 { get; set; } + [Data] public long GSReg14 { get; set; } + [Data] public Tm2.GsTex Tex0 { get; set; } + [Data] public long GSReg06 { get; set; } + [Data] public CLAMP Clamp { get; set; } + [Data] public long Data88 { get; set; } + [Data] public long Data90 { get; set; } + [Data] public long Data98 { get; set; } + } + + public enum TextureWrapMode + { + Repeat, Clamp, RegionClamp, RegionRepeat + } + + public class TextureAddressMode + { + public TextureWrapMode AddressU { get; set; } + public TextureWrapMode AddressV { get; set; } + public int Left { get; set; } + public int Top { get; set; } + public int Right { get; set; } + public int Bottom { get; set; } } public class BITBLTBUF @@ -294,7 +296,7 @@ public TEX1() { } public int L { get => GetBits(Data, 19, 2); set => Data = SetBits(Data, 19, 2, value); } public int K { get => GetBits(Data, 32, 12); set => Data = SetBits(Data, 32, 12, value); } } - + public class CLAMP { [Data] public long Data { get; set; } @@ -389,93 +391,93 @@ public ClutAlloc Allocate(bool isIndexed4) return entry; } } - - private const int MagicCode = 0; - private const int HeaderLength = 0x24; - - private DataTransferInfo _clutTransfer; - private List _textureTransfer; - private List _gsInfo; - + + private const int MagicCode = 0; + private const int HeaderLength = 0x24; + + private DataTransferInfo _clutTransfer; + private List _textureTransfer; + private List _gsInfo; + /// /// 0x74 of DataTransfer will be relative to offset from zero position. /// private bool _useRelativeOffset; - - public List Images { get; } - - private byte[] OffsetData { get; } - private byte[] PictureData { get; } - private byte[] PaletteData { get; } - - public TextureFooterData TextureFooterData { get; set; } + + public List Images { get; } + + private byte[] OffsetData { get; } + private byte[] PictureData { get; } + private byte[] PaletteData { get; } + + public TextureFooterData TextureFooterData { get; set; } private const int ClutBasePtr = 0x2C00; private const int TexBasePtr = 0x3000; - private ModelTexture(Stream stream) - { - var header = BinaryMapping.ReadObject
(stream.SetPosition(0)); - if (header.MagicCode == -1) - return; - - var offset1Size = header.Texinf1off - header.Offset1; - var Texinf2offSize = header.PictureOffset - header.Texinf2off; - var pictureSize = header.PaletteOffset - header.PictureOffset; - var paletteSize = header.ColorCount * 4; - var footerSize = (int)stream.Length - (header.PaletteOffset + paletteSize); - if (footerSize < 0) - throw new NotFiniteNumberException("Invalid texture"); - - stream.Position = header.Offset1; - OffsetData = stream.ReadBytes(header.GsInfoCount); - - stream.Position = header.Texinf1off; - _clutTransfer = BinaryMapping.ReadObject<_DataTransfer>(stream).ToInfo(); - _textureTransfer = Enumerable.Range(0, header.TextureInfoCount) - .Select(_ => BinaryMapping.ReadObject<_DataTransfer>(stream).ToInfo()) - .ToList(); - - stream.Position = header.Texinf2off; - _gsInfo = Enumerable.Range(0, header.GsInfoCount) - .Select(_ => BinaryMapping.ReadObject<_GsInfo>(stream)) - .Select(x => new GsInfo - { - MipTbp1 = x.MipTbp1, - MipTbp2 = x.MipTbp2, - Tex2 = x.Tex2, - Tex1 = x.Tex1, - Tex0 = x.Tex0, - AddressMode = ClampFromGs(x.Clamp.Data), - }) - .ToList(); - - stream.Position = header.PictureOffset; - PictureData = stream.ReadBytes(pictureSize); - - stream.Position = header.PaletteOffset; - PaletteData = stream.ReadBytes(paletteSize); - - TextureFooterData = TextureFooterData.Read(stream); - - var paletteBaseOffset = _clutTransfer.BitBltBuf.DBP; - - Images = new List(); - for (var i = 0; i < header.GsInfoCount; i++) - { - var texInfo = _textureTransfer[OffsetData[i]]; - var gsInfo = _gsInfo[i]; - var gsTex = gsInfo.Tex0; - - var width = 1 << gsTex.TW; - var height = 1 << gsTex.TH; - var pixelFormat = GetPixelFormat(gsTex.PSM); - var uploadPixelFormat = (Tm2.GsPSM)texInfo.BitBltBuf.DPSM; - var dataLength = width * height / (pixelFormat == PixelFormat.Indexed4 ? 2 : 1); - var data = stream.SetPosition(texInfo.DataOffset).ReadBytes(dataLength); - - Images.Add(new Texture(width, height, pixelFormat, uploadPixelFormat, data, PaletteData, gsInfo.AddressMode, gsTex.CBP - paletteBaseOffset, gsTex.CSA)); - } + private ModelTexture(Stream stream) + { + var header = BinaryMapping.ReadObject
(stream.SetPosition(0)); + if (header.MagicCode == -1) + return; + + var offset1Size = header.Texinf1off - header.Offset1; + var Texinf2offSize = header.PictureOffset - header.Texinf2off; + var pictureSize = header.PaletteOffset - header.PictureOffset; + var paletteSize = header.ColorCount * 4; + var footerSize = (int)stream.Length - (header.PaletteOffset + paletteSize); + if (footerSize < 0) + throw new NotFiniteNumberException("Invalid texture"); + + stream.Position = header.Offset1; + OffsetData = stream.ReadBytes(header.GsInfoCount); + + stream.Position = header.Texinf1off; + _clutTransfer = BinaryMapping.ReadObject<_DataTransfer>(stream).ToInfo(); + _textureTransfer = Enumerable.Range(0, header.TextureInfoCount) + .Select(_ => BinaryMapping.ReadObject<_DataTransfer>(stream).ToInfo()) + .ToList(); + + stream.Position = header.Texinf2off; + _gsInfo = Enumerable.Range(0, header.GsInfoCount) + .Select(_ => BinaryMapping.ReadObject<_GsInfo>(stream)) + .Select(x => new GsInfo + { + MipTbp1 = x.MipTbp1, + MipTbp2 = x.MipTbp2, + Tex2 = x.Tex2, + Tex1 = x.Tex1, + Tex0 = x.Tex0, + AddressMode = ClampFromGs(x.Clamp.Data), + }) + .ToList(); + + stream.Position = header.PictureOffset; + PictureData = stream.ReadBytes(pictureSize); + + stream.Position = header.PaletteOffset; + PaletteData = stream.ReadBytes(paletteSize); + + TextureFooterData = TextureFooterData.Read(stream); + + var paletteBaseOffset = _clutTransfer.BitBltBuf.DBP; + + Images = new List(); + for (var i = 0; i < header.GsInfoCount; i++) + { + var texInfo = _textureTransfer[OffsetData[i]]; + var gsInfo = _gsInfo[i]; + var gsTex = gsInfo.Tex0; + + var width = 1 << gsTex.TW; + var height = 1 << gsTex.TH; + var pixelFormat = GetPixelFormat(gsTex.PSM); + var uploadPixelFormat = (Tm2.GsPSM)texInfo.BitBltBuf.DPSM; + var dataLength = width * height / (pixelFormat == PixelFormat.Indexed4 ? 2 : 1); + var data = stream.SetPosition(texInfo.DataOffset).ReadBytes(dataLength); + + Images.Add(new Texture(width, height, pixelFormat, uploadPixelFormat, data, PaletteData, gsInfo.AddressMode, gsTex.CBP - paletteBaseOffset, gsTex.CSA)); + } } public class Build @@ -483,16 +485,16 @@ public class Build public IList images; public byte[] offsetData; public IList textureTransfer; - public IList gsInfo; - public byte[] footerData; + public IList gsInfo; + public byte[] footerData; } public class UserDataTransferInfo { - public BITBLTBUF BitBltBuf { get; set; } = new BITBLTBUF(); + public BITBLTBUF BitBltBuf { get; set; } = new BITBLTBUF(); public TRXPOS TrxPos { get; set; } = new TRXPOS(); - public TRXREG TrxReg { get; set; } = new TRXREG(); - public TRXDIR TrxDir { get; set; } = new TRXDIR(); + public TRXREG TrxReg { get; set; } = new TRXREG(); + public TRXDIR TrxDir { get; set; } = new TRXDIR(); public UserDataTransferInfo() { @@ -694,9 +696,9 @@ private static Tm2.GsPSM ToPSM(PixelFormat pixelFormat) { switch (pixelFormat) { - case PixelFormat.Indexed4: + case PixelFormat.Indexed4: return Tm2.GsPSM.GS_PSMT4; - case PixelFormat.Indexed8: + case PixelFormat.Indexed8: return Tm2.GsPSM.GS_PSMT8; } throw new NotSupportedException(); @@ -782,14 +784,14 @@ public void Write(Stream stream) var paletteOffset = (int)stream.Position; stream.Write(PaletteData); - - if (TextureFooterData != null) - { - TextureFooterData.Write(stream); - } - else - { - stream.Write(Encoding.ASCII.GetBytes("_KN5")); + + if (TextureFooterData != null) + { + TextureFooterData.Write(stream); + } + else + { + stream.Write(Encoding.ASCII.GetBytes("_KN5")); } var writer = new BinaryWriter(stream.SetPosition(0)); @@ -869,9 +871,9 @@ private static PixelFormat GetPixelFormat(Tm2.GsPSM psm) { switch (psm) { - case Tm2.GsPSM.GS_PSMT8: + case Tm2.GsPSM.GS_PSMT8: return PixelFormat.Indexed8; - case Tm2.GsPSM.GS_PSMT4: + case Tm2.GsPSM.GS_PSMT4: return PixelFormat.Indexed4; default: throw new NotSupportedException($"GsPSM format {psm} not supported"); @@ -966,8 +968,8 @@ private static long SetBits(long Data, int position, int size, int value) { var mask = (1 << size) - 1U; return Data & ~(mask << position) | ((value & mask) << position); - } - - public ushort GetGsInfoCount() => Convert.ToUInt16(_gsInfo.Count); - } -} + } + + public ushort GetGsInfoCount() => Convert.ToUInt16(_gsInfo.Count); + } +} diff --git a/OpenKh.Kh2/RawBitmap.cs b/OpenKh.Kh2/RawBitmap.cs index fdb7571ea..ebc7b7756 100644 --- a/OpenKh.Kh2/RawBitmap.cs +++ b/OpenKh.Kh2/RawBitmap.cs @@ -50,6 +50,8 @@ private RawBitmap(Stream stream, int width, int height, bool is8bit, bool defaul public PixelFormat PixelFormat { get; } + public PixelFormat ClutFormat => PixelFormat.Rgba8888; + public byte[] GetClut() { switch (PixelFormat) diff --git a/OpenKh.Tests.Engine/ImageReadExtensionsTests.cs b/OpenKh.Tests.Engine/ImageReadExtensionsTests.cs index eaa58b878..298a9af30 100644 --- a/OpenKh.Tests.Engine/ImageReadExtensionsTests.cs +++ b/OpenKh.Tests.Engine/ImageReadExtensionsTests.cs @@ -18,6 +18,7 @@ private class TestImager : IImageRead { public Size Size { get; set; } public PixelFormat PixelFormat { get; set; } + public PixelFormat ClutFormat { get; set; } public byte[] ClutPassThru { get; set; } public byte[] DataPassThru { get; set; } @@ -32,6 +33,7 @@ public void AsBgra8888Indexed4Test() { Size = new Size(2, 1), PixelFormat = PixelFormat.Indexed4, + ClutFormat = PixelFormat.Rgba8888, DataPassThru = new byte[] { 0x10 }, ClutPassThru = new byte[] { @@ -59,6 +61,7 @@ public void AsBgra8888Indexed8Test() { Size = new Size(2, 1), PixelFormat = PixelFormat.Indexed8, + ClutFormat = PixelFormat.Rgba8888, DataPassThru = new byte[] { 1, 0 }, ClutPassThru = new byte[] { @@ -86,6 +89,7 @@ public void AsBgra8888Rgba8888Test() { Size = new Size(2, 1), PixelFormat = PixelFormat.Rgba8888, + ClutFormat = PixelFormat.Undefined, DataPassThru = new byte[] { // B G R A 0x88, 0x44, 0x22, 0x11, // 0 @@ -110,6 +114,7 @@ public void AsRgba8888Indexed4Test() { Size = new Size(2, 1), PixelFormat = PixelFormat.Indexed4, + ClutFormat = PixelFormat.Rgba8888, DataPassThru = new byte[] { 0x10 }, ClutPassThru = new byte[] { @@ -137,6 +142,7 @@ public void AsRgba8888Indexed8Test() { Size = new Size(2, 1), PixelFormat = PixelFormat.Indexed8, + ClutFormat = PixelFormat.Rgba8888, DataPassThru = new byte[] { 1, 0 }, ClutPassThru = new byte[] { @@ -164,6 +170,7 @@ public void AsRgba8888Rgba8888Test() { Size = new Size(2, 1), PixelFormat = PixelFormat.Rgba8888, + ClutFormat = PixelFormat.Undefined, DataPassThru = new byte[] { // B G R A 0x22, 0x44, 0x88, 0x11, // 0 diff --git a/OpenKh.Tests/Imaging/ImageDecodeTests.cs b/OpenKh.Tests/Imaging/ImageDecodeTests.cs index 9c18b9fb0..80be25dc6 100644 --- a/OpenKh.Tests/Imaging/ImageDecodeTests.cs +++ b/OpenKh.Tests/Imaging/ImageDecodeTests.cs @@ -10,6 +10,7 @@ public class Fake4bppImage : IImageRead { public Size Size => new Size(Width, Height); public PixelFormat PixelFormat => PixelFormat.Indexed4; + public PixelFormat ClutFormat => PixelFormat.Rgba8888; public byte[] GetData() => Data4bpp; public byte[] GetClut() => Clut4bpp; } diff --git a/OpenKh.Tests/Imaging/ImageExtensionsTests.cs b/OpenKh.Tests/Imaging/ImageExtensionsTests.cs index 11b91f873..9546e36f7 100644 --- a/OpenKh.Tests/Imaging/ImageExtensionsTests.cs +++ b/OpenKh.Tests/Imaging/ImageExtensionsTests.cs @@ -15,6 +15,7 @@ private class TestImager : IImageRead { public Size Size { get; set; } public PixelFormat PixelFormat { get; set; } + public PixelFormat ClutFormat { get; set; } public byte[] ClutPassThru { get; set; } public byte[] DataPassThru { get; set; } @@ -29,6 +30,7 @@ public void ToBgra32Indexed4Test() { Size = new Size(2, 1), PixelFormat = PixelFormat.Indexed4, + ClutFormat = PixelFormat.Rgba8888, DataPassThru = new byte[] { 0x10 }, ClutPassThru = new byte[] { @@ -56,6 +58,7 @@ public void ToBgra32Indexed8Test() { Size = new Size(2, 1), PixelFormat = PixelFormat.Indexed8, + ClutFormat = PixelFormat.Rgba8888, DataPassThru = new byte[] { 1, 0 }, ClutPassThru = new byte[] { @@ -83,6 +86,7 @@ public void ToBgra32Rgba8888Test() { Size = new Size(2, 1), PixelFormat = PixelFormat.Rgba8888, + ClutFormat = PixelFormat.Undefined, DataPassThru = new byte[] { // B G R A 0x88, 0x44, 0x22, 0x11, // 0 diff --git a/OpenKh.Tests/Imaging/PngTests.cs b/OpenKh.Tests/Imaging/PngTests.cs index ec04d9b8e..3e971c443 100644 --- a/OpenKh.Tests/Imaging/PngTests.cs +++ b/OpenKh.Tests/Imaging/PngTests.cs @@ -376,6 +376,7 @@ private class Bitmap1x1_32 : IImageRead { public Size Size => new Size(1, 1); public PixelFormat PixelFormat => PixelFormat.Rgba8888; + public PixelFormat ClutFormat => PixelFormat.Undefined; public byte[] GetClut() => null; public byte[] GetData() => new byte[] { 0x44, 0x22, 0x11, 0x88 }; @@ -401,6 +402,7 @@ private class Bitmap1x1_24 : IImageRead { public Size Size => new Size(1, 1); public PixelFormat PixelFormat => PixelFormat.Rgb888; + public PixelFormat ClutFormat => PixelFormat.Undefined; public byte[] GetClut() => null; public byte[] GetData() => new byte[] { 0x44, 0x22, 0x11 }; @@ -426,6 +428,7 @@ private class Bitmap4x4_4 : IImageRead { public Size Size => new Size(4, 4); public PixelFormat PixelFormat => PixelFormat.Indexed4; + public PixelFormat ClutFormat => PixelFormat.Rgba8888; public byte[] GetClut() => new byte[] { 0x00, 0x00, 0x00, 0xFF, @@ -473,6 +476,7 @@ private class Bitmap16x16_8 : IImageRead { public Size Size => new Size(16, 16); public PixelFormat PixelFormat => PixelFormat.Indexed8; + public PixelFormat ClutFormat => PixelFormat.Rgba8888; public byte[] GetClut() => Enumerable.Range(0, 256) .SelectMany(index => new byte[] { (byte)index, 0, 0, 255 }) diff --git a/OpenKh.Tests/kh2/FontContextTests.cs b/OpenKh.Tests/kh2/FontContextTests.cs index 178e84cf0..28856963c 100644 --- a/OpenKh.Tests/kh2/FontContextTests.cs +++ b/OpenKh.Tests/kh2/FontContextTests.cs @@ -1,4 +1,4 @@ -using OpenKh.Imaging; +using OpenKh.Imaging; using OpenKh.Kh2; using OpenKh.Kh2.Contextes; using System; @@ -46,7 +46,7 @@ private static void LoadFontTest( int expectedHeight, int bitsPerPixel, string name, - Func getter) + Func getter) { var expectedLength = expectedWidth * expectedHeight * bitsPerPixel / 8; diff --git a/OpenKh.Tests/kh2/ImageReadExtensionsTests.cs b/OpenKh.Tests/kh2/ImageReadExtensionsTests.cs index 33251cdd6..985e2d305 100644 --- a/OpenKh.Tests/kh2/ImageReadExtensionsTests.cs +++ b/OpenKh.Tests/kh2/ImageReadExtensionsTests.cs @@ -1,4 +1,4 @@ -using OpenKh.Common; +using OpenKh.Common; using OpenKh.Imaging; using OpenKh.Kh2; using OpenKh.Kh2.Extensions; @@ -18,6 +18,7 @@ class SampleImager : IImageRead public Size Size { get; set; } public PixelFormat PixelFormat { get; set; } + public PixelFormat ClutFormat { get; set; } public byte[] ForGetClut { get; set; } public byte[] ForGetData { get; set; } @@ -34,6 +35,7 @@ public void SampleRgba8888AsImgd() new SampleImager { PixelFormat = PixelFormat.Rgba8888, + ClutFormat = PixelFormat.Undefined, Size = new Size(1, 1), ForGetData = new byte[] { diff --git a/OpenKh.Tools.Common/Imaging/GdiImage.cs b/OpenKh.Tools.Common/Imaging/GdiImage.cs index b58bbb12f..ff10044c3 100644 --- a/OpenKh.Tools.Common/Imaging/GdiImage.cs +++ b/OpenKh.Tools.Common/Imaging/GdiImage.cs @@ -22,6 +22,8 @@ public GdiImage(Stream stream) public OpenKh.Imaging.PixelFormat PixelFormat => _bitmap.PixelFormat.GetPixelFormat(); + public OpenKh.Imaging.PixelFormat ClutFormat => OpenKh.Imaging.PixelFormat.Rgba8888; + public byte[] GetClut() { var palette = _bitmap.Palette?.Entries ?? new Color[0]; From c31a5341b7ee43d98f6cb232b22848a3fd8ab1b0 Mon Sep 17 00:00:00 2001 From: Thomas Casson Date: Sat, 20 Jan 2024 18:54:22 +0000 Subject: [PATCH 2/3] Rename IImageRead to IImage --- OpenKh.Bbs/FontsArc.cs | 8 ++--- .../Utils/ImgdBitmapUtil.cs | 6 ++-- .../Utils/QuantizerFactory.cs | 8 ++--- .../Utils/SpriteImageUtil.cs | 4 +-- OpenKh.Engine.MonoGame/Extensions.cs | 2 +- OpenKh.Engine.MonoGame/MonoSpriteDrawing.cs | 2 +- .../Extensions/ImageReadExtensions.cs | 4 +-- OpenKh.Engine/Renders/ISpriteDrawing.cs | 2 +- OpenKh.Engine/Renders/Kh2MessageRenderer.cs | 14 ++++----- OpenKh.Imaging/{IImageRead.cs => IImage.cs} | 2 +- OpenKh.Imaging/ImageExtensions.cs | 2 +- OpenKh.Imaging/PngImage.cs | 4 +-- OpenKh.Imaging/SimpleImage.cs | 2 +- OpenKh.Kh2/Contextes/FontContext.cs | 30 +++++++++---------- OpenKh.Kh2/Extensions/ImageReadExtensions.cs | 2 +- OpenKh.Kh2/Imgd.cs | 2 +- OpenKh.Kh2/ModelTexture.cs | 2 +- OpenKh.Kh2/RawBitmap.cs | 2 +- .../ImageReadExtensionsTests.cs | 2 +- OpenKh.Tests/Imaging/ImageDecodeTests.cs | 2 +- OpenKh.Tests/Imaging/ImageExtensionsTests.cs | 2 +- OpenKh.Tests/Imaging/PngTests.cs | 8 ++--- OpenKh.Tests/kh2/FontContextTests.cs | 2 +- OpenKh.Tests/kh2/ImageReadExtensionsTests.cs | 2 +- .../ImageReadExtensions.cs | 2 +- OpenKh.Tools.Common/Imaging/GdiFormats.cs | 12 ++++---- OpenKh.Tools.Common/Imaging/GdiImage.cs | 2 +- .../Imaging/ImageExtensions.cs | 4 +-- .../SpriteDrawingDirect3D.Surface.cs | 2 +- .../ViewModels/FontEntryViewModel.cs | 4 +-- .../Models/TexturesModel.cs | 4 +-- .../Services/IImageContainer.cs | 4 +-- .../Services/IImageSingle.cs | 4 +-- .../ImageFormatService.ImageContainer.cs | 8 ++--- .../ImageFormatService.SingleImageFormat.cs | 12 ++++---- .../Services/ImageFormatService.cs | 2 +- .../Services/ImageFormatSevice.Kh2Font.cs | 4 +-- .../ViewModels/ImageViewModel.cs | 4 +-- .../ViewModels/ImageViewerViewModel.cs | 28 ++++++++--------- OpenKh.WinShell.IMDUtilities/IMDThumbnail.cs | 4 +-- 40 files changed, 108 insertions(+), 108 deletions(-) rename OpenKh.Imaging/{IImageRead.cs => IImage.cs} (96%) diff --git a/OpenKh.Bbs/FontsArc.cs b/OpenKh.Bbs/FontsArc.cs index 0f6ac9fd1..6980a4564 100644 --- a/OpenKh.Bbs/FontsArc.cs +++ b/OpenKh.Bbs/FontsArc.cs @@ -10,7 +10,7 @@ namespace OpenKh.Bbs { public class FontsArc { - private class Image : IImageRead + private class Image : IImage { private readonly byte[] _imageData; private readonly byte[] _clutData; @@ -59,8 +59,8 @@ internal Image(string name, Arc.Entry mtx, byte[] clut, int width, int maxHeight public class Font { public string Name { get; } - public IImageRead Image1 { get; } - public IImageRead Image2 { get; } + public IImage Image1 { get; } + public IImage Image2 { get; } public FontInfo Info { get; } public FontCharacterInfo[] CharactersInfo { get; } @@ -99,7 +99,7 @@ private FontsArc(Stream stream) FontNumeral = new Font(_entries, "numeral"); } - public IImageRead FontIcon { get; } + public IImage FontIcon { get; } public Font FontCmd { get; } public Font FontHelp { get; } public Font FontMenu { get; } diff --git a/OpenKh.Command.ImgTool/Utils/ImgdBitmapUtil.cs b/OpenKh.Command.ImgTool/Utils/ImgdBitmapUtil.cs index d5143cbaf..3dfd0ede3 100644 --- a/OpenKh.Command.ImgTool/Utils/ImgdBitmapUtil.cs +++ b/OpenKh.Command.ImgTool/Utils/ImgdBitmapUtil.cs @@ -14,7 +14,7 @@ public class ImgdBitmapUtil { class ReadAs32bppPixels { - public ReadAs32bppPixels(IImageRead bitmap) + public ReadAs32bppPixels(IImage bitmap) { Width = bitmap.Size.Width; Height = bitmap.Size.Height; @@ -88,7 +88,7 @@ public int FindNearest(uint pixel) } } - public static Imgd ToImgd(IImageRead bitmap, int bpp, Func quantizer, bool swizzle = false) + public static Imgd ToImgd(IImage bitmap, int bpp, Func quantizer, bool swizzle = false) { if (quantizer != null) { @@ -224,7 +224,7 @@ public static Imgd ToImgd(IImageRead bitmap, int bpp, Func FromFileToImgdList(string anyFile, int bitsPerPixel, Func quantizer, bool swizzle) + public static IEnumerable FromFileToImgdList(string anyFile, int bitsPerPixel, Func quantizer, bool swizzle) { switch (Path.GetExtension(anyFile).ToLowerInvariant()) { diff --git a/OpenKh.Command.ImgTool/Utils/QuantizerFactory.cs b/OpenKh.Command.ImgTool/Utils/QuantizerFactory.cs index 8a6858f77..6ec296f78 100644 --- a/OpenKh.Command.ImgTool/Utils/QuantizerFactory.cs +++ b/OpenKh.Command.ImgTool/Utils/QuantizerFactory.cs @@ -20,7 +20,7 @@ private class CommonQuantizerParam : ICommonQuantizerParam public bool PngQuant { get; set; } } - public static Func MakeFrom(int BitsPerPixel, bool InvokePngquant) => + public static Func MakeFrom(int BitsPerPixel, bool InvokePngquant) => MakeFrom( new CommonQuantizerParam { @@ -29,7 +29,7 @@ public static Func MakeFrom(int BitsPerPixel, bool Invok } ); - public static Func MakeFrom(ICommonQuantizerParam param) + public static Func MakeFrom(ICommonQuantizerParam param) { return bitmap => { @@ -97,7 +97,7 @@ public static Func MakeFrom(ICommonQuantizerParam param) }; } - private class LocalImager : IImageRead + private class LocalImager : IImage { public Size Size { get; set; } public PixelFormat PixelFormat { get; set; } @@ -110,7 +110,7 @@ private class LocalImager : IImageRead public byte[] GetData() => Data; } - private static IImageRead ConvertFrom(BitmapOutput output) + private static IImage ConvertFrom(BitmapOutput output) { var size = new Size(output.Width, output.Height); switch (output.BitsPixel) diff --git a/OpenKh.Command.TexFooter/Utils/SpriteImageUtil.cs b/OpenKh.Command.TexFooter/Utils/SpriteImageUtil.cs index a0d4eba80..5c79b891b 100644 --- a/OpenKh.Command.TexFooter/Utils/SpriteImageUtil.cs +++ b/OpenKh.Command.TexFooter/Utils/SpriteImageUtil.cs @@ -10,7 +10,7 @@ namespace OpenKh.Command.TexFooter.Utils { internal static class SpriteImageUtil { - public static IImageRead ToBitmap( + public static IImage ToBitmap( int BitsPerPixel, int SpriteWidth, int SpriteHeight, @@ -68,7 +68,7 @@ byte[] SpriteImage }; } - private class LocalBitmap : IImageRead + private class LocalBitmap : IImage { public Size Size { get; internal set; } public PixelFormat PixelFormat { get; internal set; } diff --git a/OpenKh.Engine.MonoGame/Extensions.cs b/OpenKh.Engine.MonoGame/Extensions.cs index a1f210d2f..15ada4735 100644 --- a/OpenKh.Engine.MonoGame/Extensions.cs +++ b/OpenKh.Engine.MonoGame/Extensions.cs @@ -8,7 +8,7 @@ namespace OpenKh.Engine.MonoGame { public static class Extensions { - public static Texture2D CreateTexture(this IImageRead image, GraphicsDevice graphicsDevice) + public static Texture2D CreateTexture(this IImage image, GraphicsDevice graphicsDevice) { var size = image.Size; var texture = new Texture2D(graphicsDevice, size.Width, size.Height); diff --git a/OpenKh.Engine.MonoGame/MonoSpriteDrawing.cs b/OpenKh.Engine.MonoGame/MonoSpriteDrawing.cs index ae0fc9635..bde143048 100644 --- a/OpenKh.Engine.MonoGame/MonoSpriteDrawing.cs +++ b/OpenKh.Engine.MonoGame/MonoSpriteDrawing.cs @@ -176,7 +176,7 @@ public void Dispose() _indexBuffer.Dispose(); } - public ISpriteTexture CreateSpriteTexture(IImageRead image) + public ISpriteTexture CreateSpriteTexture(IImage image) { var size = image.Size; var texture = new RenderTarget2D(_graphicsDevice, size.Width, size.Height); diff --git a/OpenKh.Engine/Extensions/ImageReadExtensions.cs b/OpenKh.Engine/Extensions/ImageReadExtensions.cs index 647e154e9..3ba65bd8a 100644 --- a/OpenKh.Engine/Extensions/ImageReadExtensions.cs +++ b/OpenKh.Engine/Extensions/ImageReadExtensions.cs @@ -9,7 +9,7 @@ public static class ImageReadExtensions private static readonly byte[] Rgba = new byte[] { 2, 1, 0, 3 }; /// `BB GG RR AA` - public static byte[] AsBgra8888(this IImageRead image) + public static byte[] AsBgra8888(this IImage image) { switch (image.PixelFormat) { @@ -28,7 +28,7 @@ public static byte[] AsBgra8888(this IImageRead image) } } - public static byte[] AsRgba8888(this IImageRead image) + public static byte[] AsRgba8888(this IImage image) { switch (image.PixelFormat) { diff --git a/OpenKh.Engine/Renders/ISpriteDrawing.cs b/OpenKh.Engine/Renders/ISpriteDrawing.cs index 31a860460..32fb8a8dd 100644 --- a/OpenKh.Engine/Renders/ISpriteDrawing.cs +++ b/OpenKh.Engine/Renders/ISpriteDrawing.cs @@ -319,7 +319,7 @@ public interface ISpriteDrawing : IDisposable { ISpriteTexture DestinationTexture { get; set; } - ISpriteTexture CreateSpriteTexture(IImageRead image); + ISpriteTexture CreateSpriteTexture(IImage image); ISpriteTexture CreateSpriteTexture(int width, int height); diff --git a/OpenKh.Engine/Renders/Kh2MessageRenderer.cs b/OpenKh.Engine/Renders/Kh2MessageRenderer.cs index bd723d79e..6209f2ac5 100644 --- a/OpenKh.Engine/Renders/Kh2MessageRenderer.cs +++ b/OpenKh.Engine/Renders/Kh2MessageRenderer.cs @@ -9,9 +9,9 @@ namespace OpenKh.Engine.Renders { public class RenderingMessageContext { - public IImageRead Font { get; set; } - public IImageRead Font2 { get; set; } - public IImageRead Icon { get; set; } + public IImage Font { get; set; } + public IImage Font2 { get; set; } + public IImage Icon { get; set; } public byte[] FontSpacing { get; set; } public byte[] IconSpacing { get; set; } public IMessageEncoder Encoder { get; set; } @@ -31,9 +31,9 @@ public class Kh2MessageRenderer : IMessageRenderer, IDisposable private readonly byte[] _fontSpacing; private readonly byte[] _iconSpacing; - private readonly IImageRead _imageFont; - private readonly IImageRead _imageFont2; - private readonly IImageRead _imageIcon; + private readonly IImage _imageFont; + private readonly IImage _imageFont2; + private readonly IImage _imageIcon; private readonly ISpriteTexture _spriteFont; private readonly ISpriteTexture _spriteFont2; private readonly ISpriteTexture _spriteIcon; @@ -237,7 +237,7 @@ protected void DrawImage(ISpriteTexture texture, double x, double y, int sourceX .Color(color) .SpriteTexture(texture)); - private void InitializeSurface(ref ISpriteTexture spriteTexture, IImageRead image) + private void InitializeSurface(ref ISpriteTexture spriteTexture, IImage image) { spriteTexture?.Dispose(); spriteTexture = _drawing?.CreateSpriteTexture(image); diff --git a/OpenKh.Imaging/IImageRead.cs b/OpenKh.Imaging/IImage.cs similarity index 96% rename from OpenKh.Imaging/IImageRead.cs rename to OpenKh.Imaging/IImage.cs index 392dc522b..504430d97 100644 --- a/OpenKh.Imaging/IImageRead.cs +++ b/OpenKh.Imaging/IImage.cs @@ -2,7 +2,7 @@ namespace OpenKh.Imaging { - public interface IImageRead + public interface IImage { Size Size { get; } diff --git a/OpenKh.Imaging/ImageExtensions.cs b/OpenKh.Imaging/ImageExtensions.cs index a125e12a6..ec709d5bc 100644 --- a/OpenKh.Imaging/ImageExtensions.cs +++ b/OpenKh.Imaging/ImageExtensions.cs @@ -4,7 +4,7 @@ namespace OpenKh.Imaging { public static class ImageExtensions { - public static byte[] ToBgra32(this IImageRead imageRead) + public static byte[] ToBgra32(this IImage imageRead) { switch (imageRead.PixelFormat) { diff --git a/OpenKh.Imaging/PngImage.cs b/OpenKh.Imaging/PngImage.cs index 33d1fcbdb..5da2271c1 100644 --- a/OpenKh.Imaging/PngImage.cs +++ b/OpenKh.Imaging/PngImage.cs @@ -13,7 +13,7 @@ namespace OpenKh.Imaging { - public class PngImage : IImageRead + public class PngImage : IImage { private byte[] _data; private byte[] _clut; @@ -394,7 +394,7 @@ public static bool IsValid(Stream stream) public void Write(Stream stream) => Write(stream, this); - public static void Write(Stream stream, IImageRead bitmap) + public static void Write(Stream stream, IImage bitmap) { BinaryMapping.WriteObject(stream, new Signature { Magic = Signature.Valid }); byte bits; diff --git a/OpenKh.Imaging/SimpleImage.cs b/OpenKh.Imaging/SimpleImage.cs index f79192205..b9948c4dc 100644 --- a/OpenKh.Imaging/SimpleImage.cs +++ b/OpenKh.Imaging/SimpleImage.cs @@ -6,7 +6,7 @@ namespace OpenKh.Imaging { - public class SimpleImage : IImageRead + public class SimpleImage : IImage { public Size Size { get; private set; } public int Width { get => Size.Width; } diff --git a/OpenKh.Kh2/Contextes/FontContext.cs b/OpenKh.Kh2/Contextes/FontContext.cs index f360b8e94..4b123c61b 100644 --- a/OpenKh.Kh2/Contextes/FontContext.cs +++ b/OpenKh.Kh2/Contextes/FontContext.cs @@ -8,20 +8,20 @@ namespace OpenKh.Kh2.Contextes { public class FontContext { - private IImageRead imageSystem; - private IImageRead imageSystem2; - private IImageRead imageEvent; - private IImageRead imageEvent2; - private IImageRead imageIcon; + private IImage imageSystem; + private IImage imageSystem2; + private IImage imageEvent; + private IImage imageEvent2; + private IImage imageIcon; private byte[] spacingSystem; private byte[] spacingEvent; private byte[] spacingIcon; - public IImageRead ImageSystem { get => imageSystem; set => imageSystem = value; } - public IImageRead ImageSystem2 { get => imageSystem2; set => imageSystem2 = value; } - public IImageRead ImageEvent { get => imageEvent; set => imageEvent = value; } - public IImageRead ImageEvent2 { get => imageEvent2; set => imageEvent2 = value; } - public IImageRead ImageIcon { get => imageIcon; set => imageIcon = value; } + public IImage ImageSystem { get => imageSystem; set => imageSystem = value; } + public IImage ImageSystem2 { get => imageSystem2; set => imageSystem2 = value; } + public IImage ImageEvent { get => imageEvent; set => imageEvent = value; } + public IImage ImageEvent2 { get => imageEvent2; set => imageEvent2 = value; } + public IImage ImageIcon { get => imageIcon; set => imageIcon = value; } public byte[] SpacingSystem { get => spacingSystem; set => spacingSystem = value; } public byte[] SpacingEvent { get => spacingEvent; set => spacingEvent = value; } @@ -52,7 +52,7 @@ public void Read(IEnumerable entries) } } - private void ReadFont(Bar.Entry entry, ref IImageRead image1, ref IImageRead image2, ref byte[] spacing) + private void ReadFont(Bar.Entry entry, ref IImage image1, ref IImage image2, ref byte[] spacing) { switch (entry.Type) { @@ -68,7 +68,7 @@ private void ReadFont(Bar.Entry entry, ref IImageRead image1, ref IImageRead ima } } - private void ReadIcon(Bar.Entry entry, ref IImageRead image, ref byte[] spacing, int width, int height) + private void ReadIcon(Bar.Entry entry, ref IImage image, ref byte[] spacing, int width, int height) { switch (entry.Type) { @@ -87,18 +87,18 @@ private static byte[] ReadSpacing(Bar.Entry entry) return new BinaryReader(entry.Stream).ReadBytes((int)entry.Stream.Length); } - private static IImageRead ReadImage8bit(Bar.Entry entry, int width, int height) + private static IImage ReadImage8bit(Bar.Entry entry, int width, int height) { return RawBitmap.Read8bit(entry.Stream, width, height); } - private static IImageRead ReadImagePalette1(Bar.Entry entry) + private static IImage ReadImagePalette1(Bar.Entry entry) { DeductImageSize((int)entry.Stream.Length, out var width, out var height); return RawBitmap.Read4bitPalette1(entry.Stream, width, height); } - private static IImageRead ReadImagePalette2(Bar.Entry entry) + private static IImage ReadImagePalette2(Bar.Entry entry) { DeductImageSize((int)entry.Stream.Length, out var width, out var height); return RawBitmap.Read4bitPalette2(entry.Stream, width, height); diff --git a/OpenKh.Kh2/Extensions/ImageReadExtensions.cs b/OpenKh.Kh2/Extensions/ImageReadExtensions.cs index f4b6d0e89..0b84c8589 100644 --- a/OpenKh.Kh2/Extensions/ImageReadExtensions.cs +++ b/OpenKh.Kh2/Extensions/ImageReadExtensions.cs @@ -5,7 +5,7 @@ namespace OpenKh.Kh2.Extensions { public static class ImageReadExtensions { - public static Imgd AsImgd(this IImageRead image, bool isSwizzled = false) + public static Imgd AsImgd(this IImage image, bool isSwizzled = false) { if (image is Imgd imgd) { diff --git a/OpenKh.Kh2/Imgd.cs b/OpenKh.Kh2/Imgd.cs index 44f13b86b..111c4f8cc 100644 --- a/OpenKh.Kh2/Imgd.cs +++ b/OpenKh.Kh2/Imgd.cs @@ -10,7 +10,7 @@ namespace OpenKh.Kh2 { - public partial class Imgd : IImageRead + public partial class Imgd : IImage { private class Header { diff --git a/OpenKh.Kh2/ModelTexture.cs b/OpenKh.Kh2/ModelTexture.cs index f1705db34..3ee89f2e4 100644 --- a/OpenKh.Kh2/ModelTexture.cs +++ b/OpenKh.Kh2/ModelTexture.cs @@ -26,7 +26,7 @@ private class Header [Data] public int PaletteOffset { get; set; } // clutDataOffset } - public class Texture : IImageRead + public class Texture : IImage { private readonly byte[] _data; private readonly byte[] _palette; diff --git a/OpenKh.Kh2/RawBitmap.cs b/OpenKh.Kh2/RawBitmap.cs index ebc7b7756..8460ca7f3 100644 --- a/OpenKh.Kh2/RawBitmap.cs +++ b/OpenKh.Kh2/RawBitmap.cs @@ -5,7 +5,7 @@ namespace OpenKh.Kh2 { - public class RawBitmap : IImageRead + public class RawBitmap : IImage { private const int PaletteCount = 256; private const int BitsPerColor = 32; diff --git a/OpenKh.Tests.Engine/ImageReadExtensionsTests.cs b/OpenKh.Tests.Engine/ImageReadExtensionsTests.cs index 298a9af30..c57dbdda7 100644 --- a/OpenKh.Tests.Engine/ImageReadExtensionsTests.cs +++ b/OpenKh.Tests.Engine/ImageReadExtensionsTests.cs @@ -14,7 +14,7 @@ namespace OpenKh.Tests.Engine { public class ImageReadExtensionsTests { - private class TestImager : IImageRead + private class TestImager : IImage { public Size Size { get; set; } public PixelFormat PixelFormat { get; set; } diff --git a/OpenKh.Tests/Imaging/ImageDecodeTests.cs b/OpenKh.Tests/Imaging/ImageDecodeTests.cs index 80be25dc6..4accc0c01 100644 --- a/OpenKh.Tests/Imaging/ImageDecodeTests.cs +++ b/OpenKh.Tests/Imaging/ImageDecodeTests.cs @@ -6,7 +6,7 @@ namespace OpenKh.Tests.Imaging { public class ImageDecodeTests { - public class Fake4bppImage : IImageRead + public class Fake4bppImage : IImage { public Size Size => new Size(Width, Height); public PixelFormat PixelFormat => PixelFormat.Indexed4; diff --git a/OpenKh.Tests/Imaging/ImageExtensionsTests.cs b/OpenKh.Tests/Imaging/ImageExtensionsTests.cs index 9546e36f7..ce3c41b2e 100644 --- a/OpenKh.Tests/Imaging/ImageExtensionsTests.cs +++ b/OpenKh.Tests/Imaging/ImageExtensionsTests.cs @@ -11,7 +11,7 @@ namespace OpenKh.Tests.Imaging { public class ImageExtensionsTests { - private class TestImager : IImageRead + private class TestImager : IImage { public Size Size { get; set; } public PixelFormat PixelFormat { get; set; } diff --git a/OpenKh.Tests/Imaging/PngTests.cs b/OpenKh.Tests/Imaging/PngTests.cs index 3e971c443..233971cf8 100644 --- a/OpenKh.Tests/Imaging/PngTests.cs +++ b/OpenKh.Tests/Imaging/PngTests.cs @@ -372,7 +372,7 @@ public void Load2x2_32() Assert.Equal(pixels, image.GetData()); } - private class Bitmap1x1_32 : IImageRead + private class Bitmap1x1_32 : IImage { public Size Size => new Size(1, 1); public PixelFormat PixelFormat => PixelFormat.Rgba8888; @@ -398,7 +398,7 @@ public void Save1x1_32() } } - private class Bitmap1x1_24 : IImageRead + private class Bitmap1x1_24 : IImage { public Size Size => new Size(1, 1); public PixelFormat PixelFormat => PixelFormat.Rgb888; @@ -424,7 +424,7 @@ public void Save1x1_24() } } - private class Bitmap4x4_4 : IImageRead + private class Bitmap4x4_4 : IImage { public Size Size => new Size(4, 4); public PixelFormat PixelFormat => PixelFormat.Indexed4; @@ -472,7 +472,7 @@ public void Save4x4_4() } } - private class Bitmap16x16_8 : IImageRead + private class Bitmap16x16_8 : IImage { public Size Size => new Size(16, 16); public PixelFormat PixelFormat => PixelFormat.Indexed8; diff --git a/OpenKh.Tests/kh2/FontContextTests.cs b/OpenKh.Tests/kh2/FontContextTests.cs index 28856963c..321588345 100644 --- a/OpenKh.Tests/kh2/FontContextTests.cs +++ b/OpenKh.Tests/kh2/FontContextTests.cs @@ -46,7 +46,7 @@ private static void LoadFontTest( int expectedHeight, int bitsPerPixel, string name, - Func getter) + Func getter) { var expectedLength = expectedWidth * expectedHeight * bitsPerPixel / 8; diff --git a/OpenKh.Tests/kh2/ImageReadExtensionsTests.cs b/OpenKh.Tests/kh2/ImageReadExtensionsTests.cs index 985e2d305..6f3f093fa 100644 --- a/OpenKh.Tests/kh2/ImageReadExtensionsTests.cs +++ b/OpenKh.Tests/kh2/ImageReadExtensionsTests.cs @@ -13,7 +13,7 @@ namespace OpenKh.Tests.kh2 { public class ImageReadExtensionsTests { - class SampleImager : IImageRead + class SampleImager : IImage { public Size Size { get; set; } diff --git a/OpenKh.Tools.Common.Wpf/ImageReadExtensions.cs b/OpenKh.Tools.Common.Wpf/ImageReadExtensions.cs index 8ed854f01..50bd73070 100644 --- a/OpenKh.Tools.Common.Wpf/ImageReadExtensions.cs +++ b/OpenKh.Tools.Common.Wpf/ImageReadExtensions.cs @@ -6,7 +6,7 @@ namespace OpenKh.Tools.Common.Wpf { public static class ImageReadExtensions { - public static BitmapSource GetBimapSource(this IImageRead imageRead) + public static BitmapSource GetBimapSource(this IImage imageRead) { const double dpi = 96.0; diff --git a/OpenKh.Tools.Common/Imaging/GdiFormats.cs b/OpenKh.Tools.Common/Imaging/GdiFormats.cs index e5d0f0288..a736ee0a4 100644 --- a/OpenKh.Tools.Common/Imaging/GdiFormats.cs +++ b/OpenKh.Tools.Common/Imaging/GdiFormats.cs @@ -20,13 +20,13 @@ public static bool IsValid(Stream stream) stream.ReadByte() == 0x0a; } - public static IImageRead Read(Stream stream) + public static IImage Read(Stream stream) { stream.Position = 0; // IsValid advances 8 bytes return new PngImage(stream); } - public static void Write(Stream stream, IImageRead image) + public static void Write(Stream stream, IImage image) { stream.Position = 0; PngImage.Write(stream, image); @@ -43,9 +43,9 @@ public static bool IsValid(Stream stream) stream.ReadByte() == 0x4d; } - public static IImageRead Read(Stream stream) => new GdiImage(stream); + public static IImage Read(Stream stream) => new GdiImage(stream); - public static void Write(Stream stream, IImageRead image) + public static void Write(Stream stream, IImage image) { using (var bitmap = image.CreateBitmap()) { @@ -71,9 +71,9 @@ public static bool IsValid(Stream stream) return false; } - public static IImageRead Read(Stream stream) => new GdiImage(stream); + public static IImage Read(Stream stream) => new GdiImage(stream); - public static void Write(Stream stream, IImageRead image) + public static void Write(Stream stream, IImage image) { using (var bitmap = image.CreateBitmap()) { diff --git a/OpenKh.Tools.Common/Imaging/GdiImage.cs b/OpenKh.Tools.Common/Imaging/GdiImage.cs index ff10044c3..1efc87d12 100644 --- a/OpenKh.Tools.Common/Imaging/GdiImage.cs +++ b/OpenKh.Tools.Common/Imaging/GdiImage.cs @@ -8,7 +8,7 @@ namespace OpenKh.Tools.Common.Imaging { [SupportedOSPlatform("windows")] - internal class GdiImage : IImageRead + internal class GdiImage : IImage { private readonly Bitmap _bitmap; diff --git a/OpenKh.Tools.Common/Imaging/ImageExtensions.cs b/OpenKh.Tools.Common/Imaging/ImageExtensions.cs index 8614bd2e8..f2edc1de3 100644 --- a/OpenKh.Tools.Common/Imaging/ImageExtensions.cs +++ b/OpenKh.Tools.Common/Imaging/ImageExtensions.cs @@ -10,7 +10,7 @@ namespace OpenKh.Tools.Common.Imaging public static class ImageExtensions { [SupportedOSPlatform("windows")] - public static void SaveImage(this IImageRead imageRead, string fileName) + public static void SaveImage(this IImage imageRead, string fileName) { using (var gdiBitmap = imageRead.CreateBitmap()) { @@ -19,7 +19,7 @@ public static void SaveImage(this IImageRead imageRead, string fileName) } [SupportedOSPlatform("windows")] - public static Bitmap CreateBitmap(this IImageRead imageRead) + public static Bitmap CreateBitmap(this IImage imageRead) { var drawingPixelFormat = imageRead.PixelFormat.GetDrawingPixelFormat(); Bitmap bitmap = new Bitmap(imageRead.Size.Width, imageRead.Size.Height, drawingPixelFormat); diff --git a/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Surface.cs b/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Surface.cs index ef948c24b..d3f430a4e 100644 --- a/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Surface.cs +++ b/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Surface.cs @@ -237,7 +237,7 @@ public void Save(string filename) } } - public ISpriteTexture CreateSpriteTexture(IImageRead image) => + public ISpriteTexture CreateSpriteTexture(IImage image) => CreateSpriteTexture(image.Size.Width, image.Size.Height, image.ToBgra32()); public ISpriteTexture CreateSpriteTexture(int width, int height) diff --git a/OpenKh.Tools.CtdEditor/ViewModels/FontEntryViewModel.cs b/OpenKh.Tools.CtdEditor/ViewModels/FontEntryViewModel.cs index 5bab4df73..595594cca 100644 --- a/OpenKh.Tools.CtdEditor/ViewModels/FontEntryViewModel.cs +++ b/OpenKh.Tools.CtdEditor/ViewModels/FontEntryViewModel.cs @@ -8,8 +8,8 @@ public class FontEntryViewModel private readonly FontsArc.Font _font; public string Name => _font.Name; - public IImageRead Font1 => _font.Image1; - public IImageRead Font2 => _font.Image2; + public IImage Font1 => _font.Image1; + public IImage Font2 => _font.Image2; public FontInfo Info => _font.Info; public FontCharacterInfo[] CharactersInfo => _font.CharactersInfo; diff --git a/OpenKh.Tools.DpdViewer/Models/TexturesModel.cs b/OpenKh.Tools.DpdViewer/Models/TexturesModel.cs index 104013806..15472da21 100644 --- a/OpenKh.Tools.DpdViewer/Models/TexturesModel.cs +++ b/OpenKh.Tools.DpdViewer/Models/TexturesModel.cs @@ -7,12 +7,12 @@ namespace OpenKh.Tools.DpdViewer.Models { public class TextureModel : BaseNotifyPropertyChanged { - public TextureModel(IImageRead image) + public TextureModel(IImage image) { MasterImage = image; } - public IImageRead MasterImage { get; } + public IImage MasterImage { get; } public string DisplayName => $"{MasterImage.Size.Width}x{MasterImage.Size.Height}"; diff --git a/OpenKh.Tools.ImageViewer/Services/IImageContainer.cs b/OpenKh.Tools.ImageViewer/Services/IImageContainer.cs index cacf01e2c..4af171562 100644 --- a/OpenKh.Tools.ImageViewer/Services/IImageContainer.cs +++ b/OpenKh.Tools.ImageViewer/Services/IImageContainer.cs @@ -7,8 +7,8 @@ public interface IImageContainer { int Count { get; } - IEnumerable Images { get; } + IEnumerable Images { get; } - IImageRead GetImage(int index); + IImage GetImage(int index); } } diff --git a/OpenKh.Tools.ImageViewer/Services/IImageSingle.cs b/OpenKh.Tools.ImageViewer/Services/IImageSingle.cs index 521ed7b95..702d3c2fa 100644 --- a/OpenKh.Tools.ImageViewer/Services/IImageSingle.cs +++ b/OpenKh.Tools.ImageViewer/Services/IImageSingle.cs @@ -5,8 +5,8 @@ namespace OpenKh.Tools.ImageViewer.Services { public interface IImageSingle : IImageFormat { - IImageRead Read(Stream stream); + IImage Read(Stream stream); - void Write(Stream stream, IImageRead image); + void Write(Stream stream, IImage image); } } diff --git a/OpenKh.Tools.ImageViewer/Services/ImageFormatService.ImageContainer.cs b/OpenKh.Tools.ImageViewer/Services/ImageFormatService.ImageContainer.cs index f0eb6fc8b..a9f7d5f56 100644 --- a/OpenKh.Tools.ImageViewer/Services/ImageFormatService.ImageContainer.cs +++ b/OpenKh.Tools.ImageViewer/Services/ImageFormatService.ImageContainer.cs @@ -8,16 +8,16 @@ public partial class ImageFormatService { internal class ImageContainer : IImageContainer { - private readonly IImageRead[] _images; + private readonly IImage[] _images; - public ImageContainer(IEnumerable images) + public ImageContainer(IEnumerable images) { _images = images.ToArray(); } public int Count => _images.Length; - public IEnumerable Images => _images; - public IImageRead GetImage(int index) => _images[index]; + public IEnumerable Images => _images; + public IImage GetImage(int index) => _images[index]; } } } diff --git a/OpenKh.Tools.ImageViewer/Services/ImageFormatService.SingleImageFormat.cs b/OpenKh.Tools.ImageViewer/Services/ImageFormatService.SingleImageFormat.cs index 0d6a3a6a9..67b136db7 100644 --- a/OpenKh.Tools.ImageViewer/Services/ImageFormatService.SingleImageFormat.cs +++ b/OpenKh.Tools.ImageViewer/Services/ImageFormatService.SingleImageFormat.cs @@ -8,24 +8,24 @@ public partial class ImageFormatService { private class SingleImageFormat : GenericImageFormat, IImageSingle { - private readonly Func read; - private readonly Action write; + private readonly Func read; + private readonly Action write; public SingleImageFormat( string name, string ext, bool isCreationSupported, Func isValid, - Func read, - Action write) : + Func read, + Action write) : base(name, ext, false, isCreationSupported, isValid) { this.read = read; this.write = write; } - public IImageRead Read(Stream stream) => read(stream); - public void Write(Stream stream, IImageRead image) => write(stream, image); + public IImage Read(Stream stream) => read(stream); + public void Write(Stream stream, IImage image) => write(stream, image); } } } diff --git a/OpenKh.Tools.ImageViewer/Services/ImageFormatService.cs b/OpenKh.Tools.ImageViewer/Services/ImageFormatService.cs index 8b441fbad..7adfdfad3 100644 --- a/OpenKh.Tools.ImageViewer/Services/ImageFormatService.cs +++ b/OpenKh.Tools.ImageViewer/Services/ImageFormatService.cs @@ -57,7 +57,7 @@ static ImageFormatService() throw new NotImplementedException()), GetImageFormat("KH2TIM", "tex", false, _ => true, - s => ModelTexture.Read(s).Images.Cast(), + s => ModelTexture.Read(s).Images.Cast(), (stream, images) => throw new NotImplementedException()), }; } diff --git a/OpenKh.Tools.ImageViewer/Services/ImageFormatSevice.Kh2Font.cs b/OpenKh.Tools.ImageViewer/Services/ImageFormatSevice.Kh2Font.cs index 3963e2d85..a7510abd6 100644 --- a/OpenKh.Tools.ImageViewer/Services/ImageFormatSevice.Kh2Font.cs +++ b/OpenKh.Tools.ImageViewer/Services/ImageFormatSevice.Kh2Font.cs @@ -20,7 +20,7 @@ private static bool IsKh2Font(Stream inputStream) .Any(x => x.Type == Bar.EntryType.RawBitmap); } - private static IEnumerable ReadKh2Font(Stream inputStream) + private static IEnumerable ReadKh2Font(Stream inputStream) { var fontContext = new FontContext(); fontContext.Read(Bar.Read(inputStream.SetPosition(0)) @@ -36,7 +36,7 @@ private static IEnumerable ReadKh2Font(Stream inputStream) }.Where(x => x != null); } - private static void WriteKh2Font(Stream outputStream, IEnumerable images) + private static void WriteKh2Font(Stream outputStream, IEnumerable images) { throw new NotImplementedException(); } diff --git a/OpenKh.Tools.ImageViewer/ViewModels/ImageViewModel.cs b/OpenKh.Tools.ImageViewer/ViewModels/ImageViewModel.cs index cd172067f..a90ed047d 100644 --- a/OpenKh.Tools.ImageViewer/ViewModels/ImageViewModel.cs +++ b/OpenKh.Tools.ImageViewer/ViewModels/ImageViewModel.cs @@ -7,14 +7,14 @@ namespace OpenKh.Tools.ImageViewer.ViewModels { public class ImageViewModel : BaseNotifyPropertyChanged { - public ImageViewModel(IImageRead image, int index = -1) + public ImageViewModel(IImage image, int index = -1) { Source = image; Bitmap = Source.GetBimapSource(); Index = index; } - public IImageRead Source { get; } + public IImage Source { get; } public BitmapSource Bitmap { get; } public int Index { get; } diff --git a/OpenKh.Tools.ImageViewer/ViewModels/ImageViewerViewModel.cs b/OpenKh.Tools.ImageViewer/ViewModels/ImageViewerViewModel.cs index 1ec963aca..a081ab820 100644 --- a/OpenKh.Tools.ImageViewer/ViewModels/ImageViewerViewModel.cs +++ b/OpenKh.Tools.ImageViewer/ViewModels/ImageViewerViewModel.cs @@ -138,7 +138,7 @@ public ImageViewerViewModel() { imageFormat.As().Write( stream, - new ImageFormatService.ImageContainer(new IImageRead[] { singleImage }) + new ImageFormatService.ImageContainer(new IImage[] { singleImage }) ); } else @@ -204,7 +204,7 @@ public ImageViewerViewModel() var newImage = CreateDummyImage(); return new EditResult { - imageList = new IImageRead[] { newImage }, + imageList = new IImage[] { newImage }, selection = newImage, }; } @@ -222,7 +222,7 @@ public ImageViewerViewModel() { return new EditResult { - imageList = new IImageRead[] { Image.Source }, + imageList = new IImage[] { Image.Source }, selection = Image.Source }; } @@ -247,7 +247,7 @@ public ImageViewerViewModel() { return new EditResult { - imageList = currentImageList.Except(new IImageRead[] { Image?.Source }) + imageList = currentImageList.Except(new IImage[] { Image?.Source }) }; } ); @@ -487,7 +487,7 @@ private void LoadImage(Stream stream) } } - private IImageRead CreateDummyImage() + private IImage CreateDummyImage() => Imgd.Create( new System.Drawing.Size(128, 128), PixelFormat.Indexed8, @@ -498,13 +498,13 @@ private IImageRead CreateDummyImage() class EditResult { - internal IEnumerable imageList; - internal IImageRead selection; + internal IEnumerable imageList; + internal IImage selection; } - private void EditImageList(Func, EditResult> editor) + private void EditImageList(Func, EditResult> editor) { - var currentImageList = (ImageContainer?.Images.ToList()) ?? new List(); + var currentImageList = (ImageContainer?.Images.ToList()) ?? new List(); var currentIndex = currentImageList.IndexOf(Image?.Source); var editResult = editor(currentImageList); @@ -546,7 +546,7 @@ private void AddEmptyImage(AddPosition addPosition) EditImageList( imageList => { - var incomingImages = new IImageRead[] { CreateDummyImage() }; + var incomingImages = new IImage[] { CreateDummyImage() }; var position = Math.Max(0, imageList.IndexOf(Image?.Source)); switch (addPosition) @@ -584,7 +584,7 @@ private void AddImage(AddPosition addPosition) var incomingImages = imageFormat.IsContainer ? imageFormat.As().Read(stream).Images - : new IImageRead[] { imageFormat.As().Read(stream) }; + : new IImage[] { imageFormat.As().Read(stream) }; EditImageList( imageList => @@ -665,7 +665,7 @@ public RunCmd(string app, string arg) } } - private IEnumerable GetImagesForExport() + private IEnumerable GetImagesForExport() { if (ImageContainer != null) { @@ -675,10 +675,10 @@ private IEnumerable GetImagesForExport() if (Image?.Source != null) { // currently single image format - return new IImageRead[] { Image.Source }; + return new IImage[] { Image.Source }; } // no image loaded - return new IImageRead[0]; + return new IImage[0]; } } } diff --git a/OpenKh.WinShell.IMDUtilities/IMDThumbnail.cs b/OpenKh.WinShell.IMDUtilities/IMDThumbnail.cs index 916f64c44..bf44d917f 100644 --- a/OpenKh.WinShell.IMDUtilities/IMDThumbnail.cs +++ b/OpenKh.WinShell.IMDUtilities/IMDThumbnail.cs @@ -16,7 +16,7 @@ namespace OpenKh.WinShell.IMDUtilities [COMServerAssociation(AssociationType.FileExtension, ".imd")] public class IMDThumbnail : SharpThumbnailHandler { - Lazy _tImage; + Lazy _tImage; Lazy _rBitmap; protected override Bitmap GetThumbnailImage(uint width) { @@ -25,7 +25,7 @@ protected override Bitmap GetThumbnailImage(uint width) SelectedItemStream.CopyTo(_cStream); SelectedItemStream.Dispose(); - _tImage = new Lazy(() => Imgd.Read(_cStream)); + _tImage = new Lazy(() => Imgd.Read(_cStream)); var size = _tImage.Value.Size; var data = _tImage.Value.ToBgra32(); From 335f90d110341ad58df09c7aedb8387cfd5702cc Mon Sep 17 00:00:00 2001 From: Thomas Casson Date: Wed, 24 Jan 2024 19:22:01 +0000 Subject: [PATCH 3/3] ImageViewer can now export TM2 files. --- OpenKh.Imaging/Tm2.cs | 141 ++++++++++++++++-- .../Services/ImageFormatService.cs | 13 +- 2 files changed, 137 insertions(+), 17 deletions(-) diff --git a/OpenKh.Imaging/Tm2.cs b/OpenKh.Imaging/Tm2.cs index e7882ab9d..181449385 100644 --- a/OpenKh.Imaging/Tm2.cs +++ b/OpenKh.Imaging/Tm2.cs @@ -8,7 +8,7 @@ namespace OpenKh.Imaging { - public class Tm2 : IImageRead + public class Tm2 : IImage { private const uint MagicCode = 0x324D4954U; private const int Version = 4; @@ -87,6 +87,9 @@ public enum GsPSM GS_PSMZ16S = 58, }; + /// + /// CLuT Pixel Storage Mode + /// public enum GsCPSM { GS_PSMCT32 = 0, // 32bit RGBA @@ -95,6 +98,9 @@ public enum GsCPSM GS_PSMCT16S = 10, } + /// + /// Image Type + /// public enum IMG_TYPE { IT_RGBA = 3, @@ -102,6 +108,9 @@ public enum IMG_TYPE IT_CLUT8 = 5, }; + /// + /// CLuT Type + /// public enum CLT_TYPE { CT_A1BGR5 = 1, @@ -269,16 +278,49 @@ private class Header private class Picture { + /// + /// Total size of the Picture in bytes + /// [Data] public int TotalSize { get; set; } + /// + /// CLuT size in bytes + /// [Data] public int ClutSize { get; set; } + /// + /// Pixel data size in bytes + /// [Data] public int ImageSize { get; set; } + /// + /// Picture header size. Always 0x30 + /// [Data] public short HeaderSize { get; set; } + /// + /// Number of colors in the CLuT + /// [Data] public short ClutColorCount { get; set; } + /// + /// Picture format??? + /// [Data] public byte PictureFormat { get; set; } + /// + /// Mipmap count + /// [Data] public byte MipMapCount { get; set; } + /// + /// CLuT color format. See CLT_TYPE + /// [Data] public byte ClutType { get; set; } + /// + /// Image color format. See IMG_TYPE + /// [Data] public byte ImageType { get; set; } + /// + /// Image width in pixels + /// [Data] public short Width { get; set; } + /// + /// Image height in pixels + /// [Data] public short Height { get; set; } [Data] public GsTex GsTex0 { get; set; } [Data] public GsTex GsTex1 { get; set; } @@ -370,6 +412,34 @@ private Tm2(byte[] buffer, byte[] clut, Picture picture, PixelFormat pixFormat) ImageDataHelpers.InvertRedBlueChannels(_imageData, Size, pixFormat); } + // For Create() + private Tm2(IImage image) + { + Size = image.Size; + _imageFormat = 0; + _mipMapCount = 1; + _imageType = GetImageType(image.PixelFormat); + _clutType = GetClutType(image.ClutFormat); + _gsTex0 = new GsTex + { + TW = GetSizeRegister(Size.Width), + TH = GetSizeRegister(Size.Height), + PSM = GetPixelStorageMode(image.PixelFormat), + CPSM = (GsCPSM)GetPixelStorageMode(image.ClutFormat) + }; + _gsTex1 = new GsTex(_gsTex0); + _gsReg = 0; + _gsPal = 0; + _imageData = (byte[])image.GetData().Clone(); + var clut = image.GetClut(); + if (clut != null) + _clutData = (byte[])clut.Clone(); + else + _clutData = []; + + // TODO: If pixel/clut type is 24 bit bgr it might need expanding to 32 bit xbgr + } + public static bool IsValid(Stream stream) => stream.SetPosition(0).ReadInt32() == MagicCode && stream.Length >= HeaderLength; @@ -387,17 +457,9 @@ public static Tm2 Create(byte[] buffer, short width, short height) return new Tm2(buff, clut, pic, PixelFormat.Indexed8); } - public static Tm2 Create(IImageRead image) + public static Tm2 Create(IImage image) { - byte[] buff = image.GetData(); - byte[] clut = image.GetClut(); - Picture pic = new Picture(); - pic.Width = (short)image.Size.Width; - pic.Height = (short)image.Size.Height; - pic.GsTex0 = new GsTex(); - pic.GsTex1 = new GsTex(); - pic.ClutType = 3; - return new Tm2(buff, clut, pic, PixelFormat.Indexed8); + return new Tm2(image); } public void HalvedAlpha() @@ -540,6 +602,63 @@ private static PixelFormat GetPixelFormat(int format) } } + private static byte GetImageType(PixelFormat format) + { + switch (format) + { + case PixelFormat.Rgba1555: + return 1; + case PixelFormat.Rgb888: + return 2; + case PixelFormat.Rgba8888: + return (byte)IMG_TYPE.IT_RGBA; + case PixelFormat.Indexed4: + return (byte)IMG_TYPE.IT_CLUT4; + case PixelFormat.Indexed8: + return (byte)IMG_TYPE.IT_CLUT8; + default: + throw new ArgumentOutOfRangeException($"The format ID {format} is invalid or not supported."); + } + } + + private static byte GetClutType(PixelFormat format) + { + switch (format) + { + case PixelFormat.Undefined: + return 0; + case PixelFormat.Rgba1555: + return (byte)CLT_TYPE.CT_A1BGR5; + case PixelFormat.Rgb888: + return (byte)CLT_TYPE.CT_XBGR8; + case PixelFormat.Rgba8888: + return (byte)CLT_TYPE.CT_ABGR8; + default: + throw new ArgumentOutOfRangeException($"The format ID {format} is invalid or not supported."); + } + } + + private static GsPSM GetPixelStorageMode(PixelFormat format) + { + switch (format) + { + case PixelFormat.Indexed4: + return GsPSM.GS_PSMT4; + case PixelFormat.Indexed8: + return GsPSM.GS_PSMT8; + case PixelFormat.Rgba1555: + return GsPSM.GS_PSMCT16; + case PixelFormat.Rgb888: + case PixelFormat.Rgbx8888: + return GsPSM.GS_PSMCT24; + case PixelFormat.Undefined: + case PixelFormat.Rgba8888: + return GsPSM.GS_PSMCT32; + default: + throw new ArgumentOutOfRangeException($"The format ID {format} is invalid or not supported."); + } + } + private static byte[] SortClut(byte[] clut, PixelFormat format, int colorCount) { if (colorCount != 256) diff --git a/OpenKh.Tools.ImageViewer/Services/ImageFormatService.cs b/OpenKh.Tools.ImageViewer/Services/ImageFormatService.cs index 7adfdfad3..683f75a6d 100644 --- a/OpenKh.Tools.ImageViewer/Services/ImageFormatService.cs +++ b/OpenKh.Tools.ImageViewer/Services/ImageFormatService.cs @@ -53,8 +53,9 @@ static ImageFormatService() }, (stream, images) => throw new NotImplementedException()), - GetImageFormat("TIM2", "tm2", false, Tm2.IsValid, s => Tm2.Read(s), (stream, images) => - throw new NotImplementedException()), + GetImageFormat("TIM2", "tm2", true, Tm2.IsValid, + s => Tm2.Read(s), + (stream, images) => Tm2.Write(stream, images.Select(i => Tm2.Create(i)))), GetImageFormat("KH2TIM", "tex", false, _ => true, s => ModelTexture.Read(s).Images.Cast(), @@ -82,8 +83,8 @@ private static IImageFormat GetImageFormat( string extension, bool isCreationSupported, Func isValid, - Func read, - Action write) + Func read, + Action write) { return new SingleImageFormat(name, extension, isCreationSupported, isValid, read, write); } @@ -93,8 +94,8 @@ private static IImageFormat GetImageFormat( string extension, bool isCreationSupported, Func isValid, - Func> read, - Action> write) + Func> read, + Action> write) { return new MultipleImageFormat(name, extension, isCreationSupported, isValid, stream => new ImageContainer(read(stream)),