diff --git a/3DS/GPU/Textures.cs b/3DS/GPU/Textures.cs index 4259eac..1ab6166 100644 --- a/3DS/GPU/Textures.cs +++ b/3DS/GPU/Textures.cs @@ -72,7 +72,7 @@ namespace _3DS.GPU Height = 1 << (int)Math.Ceiling(Math.Log(Height, 2)); } Bitmap bitm = new Bitmap(physicalwidth, physicalheight); - BitmapData d = bitm.LockBits(new Rectangle(0, 0, bitm.Width, bitm.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + BitmapData d = bitm.LockBits(new Rectangle(0, 0, bitm.Width, bitm.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); uint* res = (uint*)d.Scan0; int offs = Offset;//0; int stride = d.Stride / 4; @@ -90,12 +90,17 @@ namespace _3DS.GPU int y2 = i / 8; if (y + y2 >= physicalheight) continue; int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); - res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( - Data[offs + pos * 4], - Data[offs + pos * 4 + 3], - Data[offs + pos * 4 + 2], - Data[offs + pos * 4 + 1] - ); + res[(y + y2) * stride + x + x2] = + GFXUtil.ConvertColorFormat( + IOUtil.ReadU32LE(Data, offs + pos * 4), + ColorFormat.RGBA8888, + ColorFormat.ARGB8888); + /*GFXUtil.ToArgb( + Data[offs + pos * 4], + Data[offs + pos * 4 + 3], + Data[offs + pos * 4 + 2], + Data[offs + pos * 4 + 1] + );*/ } offs += 64 * 4; } @@ -113,11 +118,16 @@ namespace _3DS.GPU int y2 = i / 8; if (y + y2 >= physicalheight) continue; int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); - res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( - Data[offs + pos * 3 + 2], - Data[offs + pos * 3 + 1], - Data[offs + pos * 3 + 0] - ); + res[(y + y2) * stride + x + x2] = + GFXUtil.ConvertColorFormat( + IOUtil.ReadU24LE(Data, offs + pos * 3), + ColorFormat.RGB888, + ColorFormat.ARGB8888); + /*GFXUtil.ToArgb( + Data[offs + pos * 3 + 2], + Data[offs + pos * 3 + 1], + Data[offs + pos * 3 + 0] + );*/ } offs += 64 * 3; } @@ -136,7 +146,11 @@ namespace _3DS.GPU if (y + y2 >= physicalheight) continue; int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); res[(y + y2) * stride + x + x2] = - GFXUtil.ARGB1555ToArgb(IOUtil.ReadU16LE(Data, offs + pos * 2)); + GFXUtil.ConvertColorFormat( + IOUtil.ReadU16LE(Data, offs + pos * 2), + ColorFormat.ARGB1555, + ColorFormat.ARGB8888); + //GFXUtil.ARGB1555ToArgb(IOUtil.ReadU16LE(Data, offs + pos * 2)); } offs += 64 * 2; } @@ -155,7 +169,11 @@ namespace _3DS.GPU if (y + y2 >= physicalheight) continue; int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); res[(y + y2) * stride + x + x2] = - GFXUtil.RGB565ToArgb(IOUtil.ReadU16LE(Data, offs + pos * 2)); + GFXUtil.ConvertColorFormat( + IOUtil.ReadU16LE(Data, offs + pos * 2), + ColorFormat.RGB565, + ColorFormat.ARGB8888); + //GFXUtil.RGB565ToArgb(IOUtil.ReadU16LE(Data, offs + pos * 2)); } offs += 64 * 2; } @@ -173,12 +191,17 @@ namespace _3DS.GPU int y2 = i / 8; if (y + y2 >= physicalheight) continue; int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); - res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( - (byte)((Data[offs + pos * 2] & 0xF) * 0x11), - (byte)((Data[offs + pos * 2 + 1] >> 4) * 0x11), - (byte)((Data[offs + pos * 2 + 1] & 0xF) * 0x11), - (byte)((Data[offs + pos * 2] >> 4) * 0x11) - ); + res[(y + y2) * stride + x + x2] = + GFXUtil.ConvertColorFormat( + IOUtil.ReadU16LE(Data, offs + pos * 2), + ColorFormat.RGBA4444, + ColorFormat.ARGB8888); + /*GFXUtil.ToArgb( + (byte)((Data[offs + pos * 2] & 0xF) * 0x11), + (byte)((Data[offs + pos * 2 + 1] >> 4) * 0x11), + (byte)((Data[offs + pos * 2 + 1] & 0xF) * 0x11), + (byte)((Data[offs + pos * 2] >> 4) * 0x11) + );*/ } offs += 64 * 2; } @@ -196,11 +219,12 @@ namespace _3DS.GPU int y2 = i / 8; if (y + y2 >= physicalheight) continue; int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); - res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( + res[(y + y2) * stride + x + x2] = GFXUtil.ToColorFormat( Data[offs + pos * 2], Data[offs + pos * 2 + 1], Data[offs + pos * 2 + 1], - Data[offs + pos * 2 + 1] + Data[offs + pos * 2 + 1], + ColorFormat.ARGB8888 ); } offs += 64 * 2; @@ -219,11 +243,12 @@ namespace _3DS.GPU int y2 = i / 8; if (y + y2 >= physicalheight) continue; int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); - res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( + res[(y + y2) * stride + x + x2] = GFXUtil.ToColorFormat( Data[offs + pos * 2], Data[offs + pos * 2 + 1], Data[offs + pos * 2 + 1], - Data[offs + pos * 2 + 1] + Data[offs + pos * 2 + 1], + ColorFormat.ARGB8888 ); } offs += 64 * 2; @@ -242,10 +267,11 @@ namespace _3DS.GPU int y2 = i / 8; if (y + y2 >= physicalheight) continue; int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); - res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( + res[(y + y2) * stride + x + x2] = GFXUtil.ToColorFormat( Data[offs + pos], Data[offs + pos], - Data[offs + pos] + Data[offs + pos], + ColorFormat.ARGB8888 ); } offs += 64; @@ -264,11 +290,12 @@ namespace _3DS.GPU int y2 = i / 8; if (y + y2 >= physicalheight) continue; int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); - res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( + res[(y + y2) * stride + x + x2] = GFXUtil.ToColorFormat( Data[offs + pos], 255, 255, - 255 + 255, + ColorFormat.ARGB8888 ); } offs += 64; @@ -287,11 +314,12 @@ namespace _3DS.GPU int y2 = i / 8; if (y + y2 >= physicalheight) continue; int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); - res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( + res[(y + y2) * stride + x + x2] = GFXUtil.ToColorFormat( (byte)((Data[offs + pos] & 0xF) * 0x11), (byte)((Data[offs + pos] >> 4) * 0x11), (byte)((Data[offs + pos] >> 4) * 0x11), - (byte)((Data[offs + pos] >> 4) * 0x11) + (byte)((Data[offs + pos] >> 4) * 0x11), + ColorFormat.ARGB8888 ); } offs += 64; @@ -311,10 +339,11 @@ namespace _3DS.GPU if (y + y2 >= physicalheight) continue; int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); int shift = (pos & 1) * 4; - res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( + res[(y + y2) * stride + x + x2] = GFXUtil.ToColorFormat( (byte)(((Data[offs + pos / 2] >> shift) & 0xF) * 0x11), (byte)(((Data[offs + pos / 2] >> shift) & 0xF) * 0x11), - (byte)(((Data[offs + pos / 2] >> shift) & 0xF) * 0x11) + (byte)(((Data[offs + pos / 2] >> shift) & 0xF) * 0x11), + ColorFormat.ARGB8888 ); } offs += 64 / 2; @@ -334,11 +363,12 @@ namespace _3DS.GPU if (y + y2 >= physicalheight) continue; int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); int shift = (pos & 1) * 4; - res[(y + y2) * stride + x + x2] = GFXUtil.ToArgb( + res[(y + y2) * stride + x + x2] = GFXUtil.ToColorFormat( (byte)(((Data[offs + pos / 2] >> shift) & 0xF) * 0x11), 255, 255, - 255 + 255, + ColorFormat.ARGB8888 ); } offs += 64 / 2; @@ -405,12 +435,12 @@ namespace _3DS.GPU if ((flipbit && y3 < 2) || (!flipbit && x3 < 2)) { int add = ETC1Modifiers[Table1, val] * (neg ? -1 : 1); - c = GFXUtil.ToArgb((byte)(((alpha >> ((x3 * 4 + y3) * 4)) & 0xF) * 0x11), (byte)ColorClamp(r1 + add), (byte)ColorClamp(g1 + add), (byte)ColorClamp(b1 + add)); + c = GFXUtil.ToColorFormat((byte)(((alpha >> ((x3 * 4 + y3) * 4)) & 0xF) * 0x11), (byte)ColorClamp(r1 + add), (byte)ColorClamp(g1 + add), (byte)ColorClamp(b1 + add), ColorFormat.ARGB8888); } else { int add = ETC1Modifiers[Table2, val] * (neg ? -1 : 1); - c = GFXUtil.ToArgb((byte)(((alpha >> ((x3 * 4 + y3) * 4)) & 0xF) * 0x11), (byte)ColorClamp(r2 + add), (byte)ColorClamp(g2 + add), (byte)ColorClamp(b2 + add)); + c = GFXUtil.ToColorFormat((byte)(((alpha >> ((x3 * 4 + y3) * 4)) & 0xF) * 0x11), (byte)ColorClamp(r2 + add), (byte)ColorClamp(g2 + add), (byte)ColorClamp(b2 + add), ColorFormat.ARGB8888); } res[(i + y3) * stride + x + j + x3] = c; } @@ -479,7 +509,7 @@ namespace _3DS.GPU int y2 = i / 8; if (y + y2 >= physicalheight) continue; int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); - IOUtil.WriteU16LE(result, offs + pos * 2, GFXUtil.ArgbToRGB565(res[(y + y2) * d.Stride / 4 + x + x2])); + IOUtil.WriteU16LE(result, offs + pos * 2, (ushort)GFXUtil.ConvertColorFormat(res[(y + y2) * d.Stride / 4 + x + x2], ColorFormat.ARGB8888, ColorFormat.RGB565)); //GFXUtil.ArgbToRGB565(res[(y + y2) * d.Stride / 4 + x + x2])); } offs += 64 * 2; } diff --git a/GCNWii/GCNWii.csproj b/GCNWii/GCNWii.csproj index 1a7c5c9..4b7414d 100644 --- a/GCNWii/GCNWii.csproj +++ b/GCNWii/GCNWii.csproj @@ -21,6 +21,7 @@ DEBUG;TRACE prompt 4 + true pdbonly @@ -43,8 +44,16 @@ + + + + Form + + + BTIViewer.cs + Form @@ -59,10 +68,14 @@ + + BTIViewer.cs + RARCViewer.cs + copy "$(TargetPath)" "$(SolutionDir)\EveryFileExplorer\bin\Debug\Plugins\$(TargetFileName)" diff --git a/GCNWii/GPU/Textures.cs b/GCNWii/GPU/Textures.cs new file mode 100644 index 0000000..16dab16 --- /dev/null +++ b/GCNWii/GPU/Textures.cs @@ -0,0 +1,298 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using System.Drawing.Imaging; +using LibEveryFileExplorer.IO; +using LibEveryFileExplorer.GFX; + +namespace GCNWii.GPU +{ + public class Textures + { + public enum ImageFormat : uint + { + I4 = 0, + I8 = 1, + IA4 = 2, + IA8 = 3, + RGB565 = 4, + RGB5A3 = 5, + RGBA8 = 6, + // + CI4 = 8, + CI8 = 9, + CI14X2 = 10, + // + CMP = 14 + } + + public enum PaletteFormat : uint + { + IA8 = 0, + RGB565 = 1, + RGB5A3 = 2 + } + + private static readonly int[] Bpp = { 4, 8, 8, 16, 16, 16, 32, 0, 4, 8, 16, 0, 0, 0, 4 }; + + public static int GetBpp(ImageFormat Format) { return Bpp[(uint)Format]; } + + public static unsafe Bitmap ToBitmap(byte[] TexData, int TexOffset, byte[] PalData, int PalOffset, int Width, int Height, ImageFormat Format, PaletteFormat PalFormat, bool ExactSize = false) + { + Bitmap bitm = new Bitmap(Width, Height); + BitmapData d = bitm.LockBits(new Rectangle(0, 0, bitm.Width, bitm.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + uint* res = (uint*)d.Scan0; + int offs = TexOffset; + int stride = d.Stride / 4; + switch (Format) + { + case ImageFormat.I4: + { + for (int y = 0; y < Height; y += 8) + { + for (int x = 0; x < Width; x += 8) + { + for (int y2 = 0; y2 < 8; y2++) + { + for (int x2 = 0; x2 < 8; x2 += 2) + { + byte I1 = (byte)((TexData[offs] >> 4) * 0x11); + byte I2 = (byte)((TexData[offs] & 0xF) * 0x11); + res[(y + y2) * stride + x + x2] = GFXUtil.ToColorFormat(I1, I1, I1, ColorFormat.ARGB8888); + res[(y + y2) * stride + x + x2 + 1] = GFXUtil.ToColorFormat(I2, I2, I2, ColorFormat.ARGB8888); + offs++; + } + } + } + } + break; + } + case ImageFormat.I8: + { + for (int y = 0; y < Height; y += 4) + { + for (int x = 0; x < Width; x += 8) + { + for (int y2 = 0; y2 < 4; y2++) + { + for (int x2 = 0; x2 < 8; x2++) + { + byte I = TexData[offs]; + res[(y + y2) * stride + x + x2] = GFXUtil.ToColorFormat(I, I, I, ColorFormat.ARGB8888); + offs++; + } + } + } + } + break; + } + case ImageFormat.IA4: + { + for (int y = 0; y < Height; y += 4) + { + for (int x = 0; x < Width; x += 8) + { + for (int y2 = 0; y2 < 4; y2++) + { + for (int x2 = 0; x2 < 8; x2++) + { + byte I = (byte)((TexData[offs] & 0xF) * 0x11); + byte A = (byte)((TexData[offs] >> 4) * 0x11); + res[(y + y2) * stride + x + x2] = GFXUtil.ToColorFormat(A, I, I, I, ColorFormat.ARGB8888); + offs++; + } + } + } + } + break; + } + case ImageFormat.IA8: + { + for (int y = 0; y < Height; y += 4) + { + for (int x = 0; x < Width; x += 4) + { + for (int y2 = 0; y2 < 4; y2++) + { + for (int x2 = 0; x2 < 4; x2++) + { + byte I = TexData[offs + 1]; + byte A = TexData[offs]; + res[(y + y2) * stride + x + x2] = GFXUtil.ToColorFormat(A, I, I, I, ColorFormat.ARGB8888); + offs += 2; + } + } + } + } + break; + } + case ImageFormat.RGB565: + { + for (int y = 0; y < Height; y += 4) + { + for (int x = 0; x < Width; x += 4) + { + for (int y2 = 0; y2 < 4; y2++) + { + for (int x2 = 0; x2 < 4; x2++) + { + res[(y + y2) * stride + x + x2] = + GFXUtil.ConvertColorFormat( + IOUtil.ReadU16BE(TexData, offs), + ColorFormat.RGB565, + ColorFormat.ARGB8888); + //GFXUtil.RGB565ToArgb(IOUtil.ReadU16BE(TexData, offs)); + offs += 2; + } + } + } + } + break; + } + case ImageFormat.RGB5A3: + { + for (int y = 0; y < Height; y += 4) + { + for (int x = 0; x < Width; x += 4) + { + for (int y2 = 0; y2 < 4; y2++) + { + for (int x2 = 0; x2 < 4; x2++) + { + ushort data = IOUtil.ReadU16BE(TexData, offs); + if ((data & 0x8000) != 0) + res[(y + y2) * stride + x + x2] = + GFXUtil.ConvertColorFormat(data, ColorFormat.XRGB1555, ColorFormat.ARGB8888); + else + res[(y + y2) * stride + x + x2] = + GFXUtil.ConvertColorFormat(data, ColorFormat.ARGB3444, ColorFormat.ARGB8888); + offs += 2; + } + } + } + } + break; + } + case ImageFormat.CI4: + { + for (int y = 0; y < Height; y += 8) + { + for (int x = 0; x < Width; x += 8) + { + for (int y2 = 0; y2 < 8; y2++) + { + for (int x2 = 0; x2 < 8; x2 += 2) + { + byte index1 = (byte)(TexData[offs] >> 4); + byte index2 = (byte)(TexData[offs] & 0xF); + switch (PalFormat) + { + case PaletteFormat.RGB5A3: + { + ushort data = IOUtil.ReadU16BE(PalData, PalOffset + index1 * 2); + if ((data & 0x8000) != 0) + res[(y + y2) * stride + x + x2] = + GFXUtil.ConvertColorFormat(data, ColorFormat.XRGB1555, ColorFormat.ARGB8888); + else + res[(y + y2) * stride + x + x2] = + GFXUtil.ConvertColorFormat(data, ColorFormat.ARGB3444, ColorFormat.ARGB8888); + data = IOUtil.ReadU16BE(PalData, PalOffset + index2 * 2); + if ((data & 0x8000) != 0) + res[(y + y2) * stride + x + x2 + 1] = + GFXUtil.ConvertColorFormat(data, ColorFormat.XRGB1555, ColorFormat.ARGB8888); + else + res[(y + y2) * stride + x + x2 + 1] = + GFXUtil.ConvertColorFormat(data, ColorFormat.ARGB3444, ColorFormat.ARGB8888); + break; + } + } + offs++; + } + } + } + } + break; + } + case ImageFormat.CI8: + { + for (int y = 0; y < Height; y += 4) + { + for (int x = 0; x < Width; x += 8) + { + for (int y2 = 0; y2 < 4; y2++) + { + for (int x2 = 0; x2 < 8; x2++) + { + byte index = TexData[offs]; + switch (PalFormat) + { + case PaletteFormat.RGB5A3: + { + ushort data = IOUtil.ReadU16BE(PalData, PalOffset + index * 2); + if ((data & 0x8000) != 0) + res[(y + y2) * stride + x + x2] = + GFXUtil.ConvertColorFormat(data, ColorFormat.XRGB1555, ColorFormat.ARGB8888); + else + res[(y + y2) * stride + x + x2] = + GFXUtil.ConvertColorFormat(data, ColorFormat.ARGB3444, ColorFormat.ARGB8888); + break; + } + } + offs++; + } + } + } + } + break; + } + case ImageFormat.CMP: + for (int y = 0; y < Height; y += 8) + { + for (int x = 0; x < Width; x += 8) + { + for (int y2 = 0; y2 < 8; y2 += 4) + { + for (int x2 = 0; x2 < 8; x2 += 4) + { + ushort color0 = IOUtil.ReadU16BE(TexData, offs); + ushort color1 = IOUtil.ReadU16BE(TexData, offs + 2); + uint data = IOUtil.ReadU32BE(TexData, offs + 4); + uint[] Palette = new uint[4]; + Palette[0] = GFXUtil.ConvertColorFormat(color0, ColorFormat.RGB565, ColorFormat.ARGB8888); + Palette[1] = GFXUtil.ConvertColorFormat(color1, ColorFormat.RGB565, ColorFormat.ARGB8888); + Color a = Color.FromArgb((int)Palette[0]); + Color b = Color.FromArgb((int)Palette[1]); + if (color0 > color1)//1/3 and 2/3 + { + Palette[2] = GFXUtil.ToColorFormat((a.R * 2 + b.R * 1) / 3, (a.G * 2 + b.G * 1) / 3, (a.B * 2 + b.B * 1) / 3, ColorFormat.ARGB8888); + Palette[3] = GFXUtil.ToColorFormat((a.R * 1 + b.R * 2) / 3, (a.G * 1 + b.G * 2) / 3, (a.B * 1 + b.B * 2) / 3, ColorFormat.ARGB8888); + } + else//1/2 and transparent + { + Palette[2] = GFXUtil.ToColorFormat((a.R + b.R) / 2, (a.G + b.G) / 2, (a.B + b.B) / 2, ColorFormat.ARGB8888); + Palette[3] = 0; + } + + int q = 30; + for (int y3 = 0; y3 < 4; y3++) + { + for (int x3 = 0; x3 < 4; x3++) + { + res[(y + y2 + y3) * stride + x + x2 + x3] = Palette[(data >> q) & 3]; + q -= 2; + } + } + offs += 8; + } + } + } + } + break; + } + bitm.UnlockBits(d); + return bitm; + } + } +} diff --git a/GCNWii/JSystem/BTI.cs b/GCNWii/JSystem/BTI.cs new file mode 100644 index 0000000..2e082ba --- /dev/null +++ b/GCNWii/JSystem/BTI.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using LibEveryFileExplorer.Files; +using System.Drawing; +using GCNWii.GPU; +using System.IO; +using System.Windows.Forms; +using GCNWii.UI; + +namespace GCNWii.JSystem +{ + public class BTI : FileFormat, IConvertable, IViewable + { + public BTI(byte[] Data) + { + EndianBinaryReader er = new EndianBinaryReader(new MemoryStream(Data), Endianness.BigEndian); + try + { + Header = new BTIHeader(er); + er.BaseStream.Position = Header.TextureOffset; + int len = (int)(er.BaseStream.Length - Header.TextureOffset); + if (Header.PaletteOffset != 0) len = (int)(Header.PaletteOffset - Header.TextureOffset); + Texture = er.ReadBytes(len); + if (Header.PaletteOffset != 0) + { + er.BaseStream.Position = Header.PaletteOffset; + Palette = er.ReadBytes(Header.NrPaletteEntries * 2); + } + } + finally + { + er.Close(); + } + } + + public string GetConversionFileFilters() + { + return "Portable Network Graphics (*.png)|*.png"; + } + + public bool Convert(int FilterIndex, string Path) + { + switch (FilterIndex) + { + case 0: + File.Create(Path).Close(); + ToBitmap().Save(Path, System.Drawing.Imaging.ImageFormat.Png); + return true; + } + return false; + } + + public Form GetDialog() + { + return new BTIViewer(this); + } + + public BTIHeader Header; + public class BTIHeader + { + public BTIHeader(EndianBinaryReader er) + { + TextureFormat = (Textures.ImageFormat)er.ReadByte(); + Unknown1 = er.ReadByte(); + Width = er.ReadUInt16(); + Height = er.ReadUInt16(); + Unknown2 = er.ReadUInt16(); + Unknown3 = er.ReadByte(); + PaletteFormat = (Textures.PaletteFormat)er.ReadByte(); + NrPaletteEntries = er.ReadUInt16(); + PaletteOffset = er.ReadUInt32(); + Unknown4 = er.ReadUInt32(); + Unknown5 = er.ReadUInt16(); + Unknown6 = er.ReadUInt16(); + MipMapCount = er.ReadByte(); + Unknown7 = er.ReadByte(); + Unknown8 = er.ReadUInt16(); + TextureOffset = er.ReadUInt32(); + } + public Textures.ImageFormat TextureFormat; //1 + public Byte Unknown1; + public UInt16 Width; + public UInt16 Height; + public UInt16 Unknown2; + public Byte Unknown3; + public Textures.PaletteFormat PaletteFormat; //1 + public UInt16 NrPaletteEntries; + public UInt32 PaletteOffset; + public UInt32 Unknown4; + public UInt16 Unknown5; + public UInt16 Unknown6; + public Byte MipMapCount; + public Byte Unknown7; + public UInt16 Unknown8; + public UInt32 TextureOffset; + } + public byte[] Texture; + public byte[] Palette; + + public Bitmap ToBitmap(int Level = 0) + { + int l = Level; + uint w = Header.Width; + uint h = Header.Height; + int bpp = GPU.Textures.GetBpp(Header.TextureFormat); + int offset = 0; + while (l > 0) + { + offset += (int)(w * h * bpp / 8); + w /= 2; + h /= 2; + l--; + } + return GPU.Textures.ToBitmap(Texture, offset, Palette, 0, (int)w, (int)h, Header.TextureFormat, Header.PaletteFormat); + } + + public class BTIIdentifier : FileFormatIdentifier + { + public override string GetCategory() + { + return Category_Graphics; + } + + public override string GetFileDescription() + { + return "Binary Texture Image (BTI)"; + } + + public override string GetFileFilter() + { + return "Binary Texture Image (*.bti)|*.bti"; + } + + public override Bitmap GetIcon() + { + return null; + } + + public override FormatMatch IsFormat(EFEFile File) + { + if (File.Name.ToLower().EndsWith(".bti")) return FormatMatch.Extension; + return FormatMatch.No; + } + } + } +} diff --git a/GCNWii/UI/BTIViewer.Designer.cs b/GCNWii/UI/BTIViewer.Designer.cs new file mode 100644 index 0000000..3befdc5 --- /dev/null +++ b/GCNWii/UI/BTIViewer.Designer.cs @@ -0,0 +1,66 @@ +namespace GCNWii.UI +{ + partial class BTIViewer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BTIViewer)); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // pictureBox1 + // + this.pictureBox1.BackColor = System.Drawing.Color.White; + this.pictureBox1.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("pictureBox1.BackgroundImage"))); + this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill; + this.pictureBox1.Location = new System.Drawing.Point(0, 0); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(565, 386); + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; + this.pictureBox1.TabIndex = 0; + this.pictureBox1.TabStop = false; + // + // CLIMViewer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(565, 386); + this.Controls.Add(this.pictureBox1); + this.Name = "CLIMViewer"; + this.Text = "CLIMViewer"; + this.Load += new System.EventHandler(this.CLIMViewer_Load); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.PictureBox pictureBox1; + } +} \ No newline at end of file diff --git a/GCNWii/UI/BTIViewer.cs b/GCNWii/UI/BTIViewer.cs new file mode 100644 index 0000000..b6b1c3d --- /dev/null +++ b/GCNWii/UI/BTIViewer.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using GCNWii.JSystem; + +namespace GCNWii.UI +{ + public partial class BTIViewer : Form + { + BTI Image; + public BTIViewer(BTI Image) + { + this.Image = Image; + InitializeComponent(); + } + + private void CLIMViewer_Load(object sender, EventArgs e) + { + pictureBox1.Image = Image.ToBitmap(); + } + } +} diff --git a/GCNWii/UI/BTIViewer.resx b/GCNWii/UI/BTIViewer.resx new file mode 100644 index 0000000..94641fc --- /dev/null +++ b/GCNWii/UI/BTIViewer.resx @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + CVKmAAAAAElFTkSuQmCC + + + \ No newline at end of file diff --git a/LibEveryFileExplorer/GFX/ColorFormat.cs b/LibEveryFileExplorer/GFX/ColorFormat.cs new file mode 100644 index 0000000..a2f11b7 --- /dev/null +++ b/LibEveryFileExplorer/GFX/ColorFormat.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace LibEveryFileExplorer.GFX +{ + public class ColorFormat + { + public readonly int AShift, ASize, RShift, RSize, GShift, GSize, BShift, BSize; + + public ColorFormat(int AShift, int ASize, int RShift, int RSize, int GShift, int GSize, int BShift, int BSize) + { + this.AShift = AShift; + this.ASize = ASize; + this.RShift = RShift; + this.RSize = RSize; + this.GShift = GShift; + this.GSize = GSize; + this.BShift = BShift; + this.BSize = BSize; + } + //The naming is based on the bit order when read out in the correct endianness + public static readonly ColorFormat ARGB8888 = new ColorFormat(24, 8, 16, 8, 8, 8, 0, 8); + + public static readonly ColorFormat ARGB3444 = new ColorFormat(12, 3, 8, 4, 4, 4, 0, 4); + + public static readonly ColorFormat RGBA8888 = new ColorFormat(0, 8, 24, 8, 16, 8, 8, 8); + + public static readonly ColorFormat RGBA4444 = new ColorFormat(0, 4, 12, 4, 8, 4, 4, 4); + + public static readonly ColorFormat RGB888 = new ColorFormat(0, 0, 16, 8, 8, 8, 0, 8); + + public static readonly ColorFormat RGB565 = new ColorFormat(0, 0, 11, 5, 5, 6, 0, 5); + + public static readonly ColorFormat ARGB1555 = new ColorFormat(15, 1, 10, 5, 5, 5, 0, 5); + public static readonly ColorFormat XRGB1555 = new ColorFormat(0, 0, 10, 5, 5, 5, 0, 5); + + public static readonly ColorFormat ABGR1555 = new ColorFormat(15, 1, 0, 5, 5, 5, 10, 5); + public static readonly ColorFormat XBGR1555 = new ColorFormat(0, 0, 0, 5, 5, 5, 10, 5); + } +} diff --git a/LibEveryFileExplorer/GFX/ETC1.cs b/LibEveryFileExplorer/GFX/ETC1.cs index 71a302c..acb15f6 100644 --- a/LibEveryFileExplorer/GFX/ETC1.cs +++ b/LibEveryFileExplorer/GFX/ETC1.cs @@ -386,12 +386,12 @@ namespace LibEveryFileExplorer.GFX if ((flipbit && y3 < 2) || (!flipbit && x3 < 2)) { int add = ETC1Modifiers[Table1, val] * (neg ? -1 : 1); - c = GFXUtil.ToArgb((byte)(((Alpha >> ((x3 * 4 + y3) * 4)) & 0xF) * 0x11), (byte)ColorClamp(r1 + add), (byte)ColorClamp(g1 + add), (byte)ColorClamp(b1 + add)); + c = GFXUtil.ToColorFormat((byte)(((Alpha >> ((x3 * 4 + y3) * 4)) & 0xF) * 0x11), (byte)ColorClamp(r1 + add), (byte)ColorClamp(g1 + add), (byte)ColorClamp(b1 + add), ColorFormat.ARGB8888); } else { int add = ETC1Modifiers[Table2, val] * (neg ? -1 : 1); - c = GFXUtil.ToArgb((byte)(((Alpha >> ((x3 * 4 + y3) * 4)) & 0xF) * 0x11), (byte)ColorClamp(r2 + add), (byte)ColorClamp(g2 + add), (byte)ColorClamp(b2 + add)); + c = GFXUtil.ToColorFormat((byte)(((Alpha >> ((x3 * 4 + y3) * 4)) & 0xF) * 0x11), (byte)ColorClamp(r2 + add), (byte)ColorClamp(g2 + add), (byte)ColorClamp(b2 + add), ColorFormat.ARGB8888); } Result[y3 * 4 + x3] = Color.FromArgb((int)c); //res[(i + y3) * stride + x + j + x3] = c; diff --git a/LibEveryFileExplorer/GFX/GFXUtil.cs b/LibEveryFileExplorer/GFX/GFXUtil.cs index f59f4f5..e8f967a 100644 --- a/LibEveryFileExplorer/GFX/GFXUtil.cs +++ b/LibEveryFileExplorer/GFX/GFXUtil.cs @@ -8,119 +8,6 @@ namespace LibEveryFileExplorer.GFX { public class GFXUtil { - /// - /// Converts the given color to the default 32bpp color format used in C#. (System.Drawing.Imaging.PixelFormat.Format32bppArgb) - /// - /// The XBGR1555 color to convert. - /// - public static uint XBGR1555ToArgb(ushort Color) - { - return ToArgb( - 255, - (byte)((Color & 0x1F) * 8), - (byte)(((Color >> 5) & 0x1F) * 8), - (byte)(((Color >> 10) & 0x1F) * 8) - ); - } - - public static ushort ArgbToXBGR1555(uint Color) - { - return (ushort)( - ((((Color >> 0) & 0xFF) >> 3) << 10) | - ((((Color >> 8) & 0xFF) >> 3) << 5) | - ((((Color >> 16) & 0xFF) >> 3) << 0)); - } - - /// - /// Converts the given color to the default 32bpp color format used in C#. (System.Drawing.Imaging.PixelFormat.Format32bppArgb) - /// - /// The ABGR1555 color to convert. - /// - public static uint ABGR1555ToArgb(ushort Color) - { - return ToArgb( - (byte)((Color >> 15) * 255), - (byte)((Color & 0x1F) * 8), - (byte)(((Color >> 5) & 0x1F) * 8), - (byte)(((Color >> 10) & 0x1F) * 8) - ); - } - - /// - /// Converts the given color to the default 32bpp color format used in C#. (System.Drawing.Imaging.PixelFormat.Format32bppArgb) - /// - /// The RGBA5551 color to convert. - /// - public static uint ARGB1555ToArgb(ushort Color) - { - return ToArgb( - (byte)((Color >> 15) * 255), - (byte)(((Color >> 10) & 0x1F) * 8), - (byte)(((Color >> 5) & 0x1F) * 8), - (byte)((Color & 0x1F) * 8) - ); - } - - /// - /// Converts the given color to the default 32bpp color format used in C#. (System.Drawing.Imaging.PixelFormat.Format32bppArgb) - /// - /// The RGB565 color to convert. - /// - public static uint RGB565ToArgb(ushort Color) - { - return ToArgb( - 255, - (byte)(((Color >> 11) & 0x1F) * 8), - (byte)(((Color >> 5) & 0x3F) * 4), - (byte)((Color & 0x1F) * 8) - ); - } - - /// - /// Converts the given color to RGB565. - /// - /// The color to convert in the default 32bpp color format used in C#. (System.Drawing.Imaging.PixelFormat.Format32bppArgb) - /// - public static ushort ArgbToRGB565(uint Color) - { - uint A = (Color >> 24) & 0xFF; - uint R = (Color >> 16) & 0xFF; - uint G = (Color >> 8) & 0xFF; - uint B = (Color >> 0) & 0xFF; - if (A < 128) { R = 0; G = 0; B = 0; } - return (ushort)((((R >> 3) << 11) | ((G >> 2) << 5) | ((B >> 3) << 0)) & 0xFFFF); - } - - /// - /// Converts the given color to the default 32bpp color format used in C# with an alpha value of 255. (System.Drawing.Imaging.PixelFormat.Format32bppArgb) - /// - /// Red - /// Green - /// Blue - /// - public static uint ToArgb(byte R, byte G, byte B) - { - return ToArgb(255, R, G, B); - } - - /// - /// Converts the given color to the default 32bpp color format used in C#. (System.Drawing.Imaging.PixelFormat.Format32bppArgb) - /// - /// Alpha - /// Red - /// Green - /// Blue - /// - public static uint ToArgb(byte A, byte R, byte G, byte B) - { - return (uint)(A << 24 | R << 16 | G << 8 | B); - } - - public static uint SetArgbAlpha(uint Argb, byte A) - { - return (uint)((uint)A << 24 | (Argb & 0xFFFFFF)); - } - public static Bitmap Resize(Bitmap Original, int Width, int Height) { if (Original.Width == Width && Original.Height == Height) return Original; @@ -135,5 +22,59 @@ namespace LibEveryFileExplorer.GFX } return res; } + + public static uint ConvertColorFormat(uint InColor, ColorFormat InputFormat, ColorFormat OutputFormat) + { + if (InputFormat == OutputFormat) return InColor; + //From color format to components: + uint A, R, G, B; + uint mask; + if (InputFormat.ASize == 0) A = 255; + else + { + mask = ~(0xFFFFFFFFu << InputFormat.ASize); + A = ((((InColor >> InputFormat.AShift) & mask) * 255u) + mask / 2) / mask; + } + mask = ~(0xFFFFFFFFu << InputFormat.RSize); + R = ((((InColor >> InputFormat.RShift) & mask) * 255u) + mask / 2) / mask; + mask = ~(0xFFFFFFFFu << InputFormat.GSize); + G = ((((InColor >> InputFormat.GShift) & mask) * 255u) + mask / 2) / mask; + mask = ~(0xFFFFFFFFu << InputFormat.BSize); + B = ((((InColor >> InputFormat.BShift) & mask) * 255u) + mask / 2) / mask; + return ToColorFormat(A, R, G, B, OutputFormat); + } + + public static uint ToColorFormat(int R, int G, int B, ColorFormat OutputFormat) + { + return ToColorFormat(255u, (uint)R, (uint)G, (uint)B, OutputFormat); + } + + public static uint ToColorFormat(int A, int R, int G, int B, ColorFormat OutputFormat) + { + return ToColorFormat((uint)A, (uint)R, (uint)G, (uint)B, OutputFormat); + } + + public static uint ToColorFormat(uint R, uint G, uint B, ColorFormat OutputFormat) + { + return ToColorFormat(255u, R, G, B, OutputFormat); + } + + public static uint ToColorFormat(uint A, uint R, uint G, uint B, ColorFormat OutputFormat) + { + uint result = 0; + uint mask; + if (OutputFormat.ASize != 0) + { + mask = ~(0xFFFFFFFFu << OutputFormat.ASize); + result |= ((A * mask + 127u) / 255u) << OutputFormat.AShift; + } + mask = ~(0xFFFFFFFFu << OutputFormat.RSize); + result |= ((R * mask + 127u) / 255u) << OutputFormat.RShift; + mask = ~(0xFFFFFFFFu << OutputFormat.GSize); + result |= ((G * mask + 127u) / 255u) << OutputFormat.GShift; + mask = ~(0xFFFFFFFFu << OutputFormat.BSize); + result |= ((B * mask + 127u) / 255u) << OutputFormat.BShift; + return result; + } } } diff --git a/LibEveryFileExplorer/IO/IOUtil.cs b/LibEveryFileExplorer/IO/IOUtil.cs index 70a9637..166f13b 100644 --- a/LibEveryFileExplorer/IO/IOUtil.cs +++ b/LibEveryFileExplorer/IO/IOUtil.cs @@ -38,17 +38,32 @@ namespace LibEveryFileExplorer.IO return (ushort)(Data[Offset] | (Data[Offset + 1] << 8)); } + public static ushort ReadU16BE(byte[] Data, int Offset) + { + return (ushort)((Data[Offset] << 8) | Data[Offset + 1]); + } + public static void WriteU16LE(byte[] Data, int Offset, ushort Value) { Data[Offset] = (byte)(Value & 0xFF); Data[Offset + 1] = (byte)((Value >> 8) & 0xFF); } + public static uint ReadU24LE(byte[] Data, int Offset) + { + return (uint)(Data[Offset] | (Data[Offset + 1] << 8) | (Data[Offset + 2] << 16)); + } + public static uint ReadU32LE(byte[] Data, int Offset) { return (uint)(Data[Offset] | (Data[Offset + 1] << 8) | (Data[Offset + 2] << 16) | (Data[Offset + 3] << 24)); } + public static uint ReadU32BE(byte[] Data, int Offset) + { + return (uint)((Data[Offset] << 24) | (Data[Offset + 1] << 16) | (Data[Offset + 2] << 8) | Data[Offset + 3]); + } + public static void WriteU32LE(byte[] Data, int Offset, uint Value) { Data[Offset] = (byte)(Value & 0xFF); diff --git a/LibEveryFileExplorer/LibEveryFileExplorer.csproj b/LibEveryFileExplorer/LibEveryFileExplorer.csproj index 6c4b579..97b80fc 100644 --- a/LibEveryFileExplorer/LibEveryFileExplorer.csproj +++ b/LibEveryFileExplorer/LibEveryFileExplorer.csproj @@ -56,6 +56,7 @@ + diff --git a/Libraries/HashTable.saht b/Libraries/HashTable.saht index e2fd820..f4390da 100644 Binary files a/Libraries/HashTable.saht and b/Libraries/HashTable.saht differ diff --git a/MarioKart/MKDS/NKM/STAG.cs b/MarioKart/MKDS/NKM/STAG.cs index 7feb7be..2164be4 100644 --- a/MarioKart/MKDS/NKM/STAG.cs +++ b/MarioKart/MKDS/NKM/STAG.cs @@ -49,12 +49,12 @@ namespace MarioKart.MKDS.NKM FogSlope = er.ReadByte(); UnknownData1 = er.ReadBytes(0x8); FogDensity = er.ReadFx32(); - FogColor = Color.FromArgb((int)GFXUtil.XBGR1555ToArgb(er.ReadUInt16())); + FogColor = Color.FromArgb((int)GFXUtil.ConvertColorFormat(er.ReadUInt16(), ColorFormat.XBGR1555, ColorFormat.ARGB8888)); FogAlpha = er.ReadUInt16(); - KclColor1 = Color.FromArgb((int)GFXUtil.XBGR1555ToArgb(er.ReadUInt16())); - KclColor2 = Color.FromArgb((int)GFXUtil.XBGR1555ToArgb(er.ReadUInt16())); - KclColor3 = Color.FromArgb((int)GFXUtil.XBGR1555ToArgb(er.ReadUInt16())); - KclColor4 = Color.FromArgb((int)GFXUtil.XBGR1555ToArgb(er.ReadUInt16())); + KclColor1 = Color.FromArgb((int)GFXUtil.ConvertColorFormat(er.ReadUInt16(), ColorFormat.XBGR1555, ColorFormat.ARGB8888)); + KclColor2 = Color.FromArgb((int)GFXUtil.ConvertColorFormat(er.ReadUInt16(), ColorFormat.XBGR1555, ColorFormat.ARGB8888)); + KclColor3 = Color.FromArgb((int)GFXUtil.ConvertColorFormat(er.ReadUInt16(), ColorFormat.XBGR1555, ColorFormat.ARGB8888)); + KclColor4 = Color.FromArgb((int)GFXUtil.ConvertColorFormat(er.ReadUInt16(), ColorFormat.XBGR1555, ColorFormat.ARGB8888)); FrustumFar = er.ReadFx32(); UnknownData2 = er.ReadBytes(0x4); } @@ -70,12 +70,12 @@ namespace MarioKart.MKDS.NKM er.Write(FogSlope); er.Write(UnknownData1, 0, 8); er.WriteFx32(FogDensity); - er.Write((UInt16)(GFXUtil.ArgbToXBGR1555((uint)FogColor.ToArgb()) | 0x8000)); + er.Write((UInt16)(GFXUtil.ConvertColorFormat((uint)FogColor.ToArgb(), ColorFormat.ARGB8888, ColorFormat.XBGR1555) | 0x8000)); er.Write(FogAlpha); - er.Write(GFXUtil.ArgbToXBGR1555((uint)KclColor1.ToArgb())); - er.Write(GFXUtil.ArgbToXBGR1555((uint)KclColor2.ToArgb())); - er.Write(GFXUtil.ArgbToXBGR1555((uint)KclColor3.ToArgb())); - er.Write(GFXUtil.ArgbToXBGR1555((uint)KclColor4.ToArgb())); + er.Write((UInt16)GFXUtil.ConvertColorFormat((uint)KclColor1.ToArgb(), ColorFormat.ARGB8888, ColorFormat.XBGR1555)); + er.Write((UInt16)GFXUtil.ConvertColorFormat((uint)KclColor2.ToArgb(), ColorFormat.ARGB8888, ColorFormat.XBGR1555)); + er.Write((UInt16)GFXUtil.ConvertColorFormat((uint)KclColor3.ToArgb(), ColorFormat.ARGB8888, ColorFormat.XBGR1555)); + er.Write((UInt16)GFXUtil.ConvertColorFormat((uint)KclColor4.ToArgb(), ColorFormat.ARGB8888, ColorFormat.XBGR1555)); er.WriteFx32(FrustumFar); er.Write(UnknownData2, 0, 4); } diff --git a/NDS/GPU/CommandContext.cs b/NDS/GPU/CommandContext.cs index 2aa2b73..6bf8f6c 100644 --- a/NDS/GPU/CommandContext.cs +++ b/NDS/GPU/CommandContext.cs @@ -294,7 +294,7 @@ namespace NDS.GPU } public void Color(uint color) { - Color(System.Drawing.Color.FromArgb((int)GFXUtil.XBGR1555ToArgb((ushort)color))); + Color(System.Drawing.Color.FromArgb((int)GFXUtil.ConvertColorFormat(color, ColorFormat.XBGR1555, ColorFormat.ARGB8888))); } public void Color(Color color) { @@ -474,8 +474,8 @@ namespace NDS.GPU ushort diff = (ushort)(cmd & 0x7FFF); bool vtx = (cmd & 0x8000) != 0; ushort amb = (ushort)((cmd >> 16) & 0x7FFF); - DiffuseColor = System.Drawing.Color.FromArgb((int)GFXUtil.XBGR1555ToArgb(diff)); - AmbientColor = System.Drawing.Color.FromArgb((int)GFXUtil.XBGR1555ToArgb(amb)); + DiffuseColor = System.Drawing.Color.FromArgb((int)GFXUtil.ConvertColorFormat(diff, ColorFormat.XBGR1555, ColorFormat.ARGB8888)); + AmbientColor = System.Drawing.Color.FromArgb((int)GFXUtil.ConvertColorFormat(amb, ColorFormat.XBGR1555, ColorFormat.ARGB8888)); if (vtx) Color(DiffuseColor); } public void MaterialColor1(uint cmd) @@ -484,8 +484,8 @@ namespace NDS.GPU bool shine = (cmd & 0x8000) != 0; ushort emiss = (ushort)((cmd >> 16) & 0x7FFF); UsesSpecularReflectionTable = shine; - SpecularColor = System.Drawing.Color.FromArgb((int)GFXUtil.XBGR1555ToArgb(spec)); - EmissionColor = System.Drawing.Color.FromArgb((int)GFXUtil.XBGR1555ToArgb(emiss)); + SpecularColor = System.Drawing.Color.FromArgb((int)GFXUtil.ConvertColorFormat(spec, ColorFormat.XBGR1555, ColorFormat.ARGB8888)); + EmissionColor = System.Drawing.Color.FromArgb((int)GFXUtil.ConvertColorFormat(emiss, ColorFormat.XBGR1555, ColorFormat.ARGB8888)); } public void Shininess(uint[] SpecReflectTable) { diff --git a/NDS/GPU/Textures.cs b/NDS/GPU/Textures.cs index 5d04130..ef62d65 100644 --- a/NDS/GPU/Textures.cs +++ b/NDS/GPU/Textures.cs @@ -364,7 +364,7 @@ namespace NDS.GPU Color[] data = new Color[Data.Length / 2]; for (int i = 0; i < Data.Length; i += 2) { - data[i / 2] = Color.FromArgb((int)GFXUtil.ABGR1555ToArgb(IOUtil.ReadU16LE(Data, i))); + data[i / 2] = Color.FromArgb((int)GFXUtil.ConvertColorFormat(IOUtil.ReadU16LE(Data, i), ColorFormat.ABGR1555, ColorFormat.ARGB8888)); } return data; } @@ -374,7 +374,7 @@ namespace NDS.GPU Color[] data = new Color[Data.Length / 2]; for (int i = 0; i < Data.Length; i += 2) { - data[i / 2] = Color.FromArgb((int)GFXUtil.XBGR1555ToArgb(IOUtil.ReadU16LE(Data, i))); + data[i / 2] = Color.FromArgb((int)GFXUtil.ConvertColorFormat(IOUtil.ReadU16LE(Data, i), ColorFormat.XBGR1555, ColorFormat.ARGB8888)); } return data; } diff --git a/NDS/UI/MDL0MaterialEditor.cs b/NDS/UI/MDL0MaterialEditor.cs index da25521..dfb8558 100644 --- a/NDS/UI/MDL0MaterialEditor.cs +++ b/NDS/UI/MDL0MaterialEditor.cs @@ -37,12 +37,12 @@ namespace NDS.UI trackBar2.Value = (int)((Material.polyAttr >> 24) & 63); checkBox1.Checked = (Material.diffAmb & 0x8000) != 0; - button1.BackColor = System.Drawing.Color.FromArgb((int)GFXUtil.XBGR1555ToArgb((ushort)(Material.diffAmb & 0x7FFF))); - button2.BackColor = System.Drawing.Color.FromArgb((int)GFXUtil.XBGR1555ToArgb((ushort)((Material.diffAmb >> 16) & 0x7FFF))); + button1.BackColor = Color.FromArgb((int)GFXUtil.ConvertColorFormat(Material.diffAmb & 0x7FFF, ColorFormat.XBGR1555, ColorFormat.ARGB8888));//(int)GFXUtil.XBGR1555ToArgb((ushort)(Material.diffAmb & 0x7FFF))); + button2.BackColor = Color.FromArgb((int)GFXUtil.ConvertColorFormat((Material.diffAmb >> 16) & 0x7FFF, ColorFormat.XBGR1555, ColorFormat.ARGB8888)); checkBox2.Checked = (Material.specEmi & 0x8000) != 0; - button3.BackColor = System.Drawing.Color.FromArgb((int)GFXUtil.XBGR1555ToArgb((ushort)(Material.specEmi & 0x7FFF))); - button4.BackColor = System.Drawing.Color.FromArgb((int)GFXUtil.XBGR1555ToArgb((ushort)((Material.specEmi >> 16) & 0x7FFF))); + button3.BackColor = Color.FromArgb((int)GFXUtil.ConvertColorFormat(Material.specEmi & 0x7FFF, ColorFormat.XBGR1555, ColorFormat.ARGB8888)); + button4.BackColor = Color.FromArgb((int)GFXUtil.ConvertColorFormat((Material.specEmi >> 16) & 0x7FFF, ColorFormat.XBGR1555, ColorFormat.ARGB8888)); uint wrapS = (Material.texImageParam >> 16) & 1; if (wrapS != 0) wrapS += (Material.texImageParam >> 18) & 1;