From 192b7d70c331331e7ec5d0faa9e8a396a021d7ac Mon Sep 17 00:00:00 2001 From: ManicSteiner Date: Sun, 9 Mar 2025 11:45:33 +0800 Subject: [PATCH] Add support of 256 color BIP --- ArcFormats/Kid/ImageBIP.cs | 104 +++++++++++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 22 deletions(-) diff --git a/ArcFormats/Kid/ImageBIP.cs b/ArcFormats/Kid/ImageBIP.cs index a3f01570..dbe809db 100644 --- a/ArcFormats/Kid/ImageBIP.cs +++ b/ArcFormats/Kid/ImageBIP.cs @@ -1,11 +1,7 @@ using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; using System.IO; -using System.Text; -using System.Windows; using System.Windows.Media; -using System.Windows.Media.Media3D; +using System.Windows.Media.Imaging; namespace GameRes.Formats.Kid { @@ -38,9 +34,18 @@ namespace GameRes.Formats.Kid return null; // throw new NotSupportedException(string.Format("BIP Chara format not supported.")); } + file.Seek(0x0C, SeekOrigin.Begin); + uint palettestart = file.ReadUInt16(); + file.Seek(0x10, SeekOrigin.Begin); uint fstart = file.ReadUInt16(); // usually 0x100 + byte bpp = 32; + if (fstart - palettestart == 1024) + { + bpp = 8; + } + // Non-Sequential read file.Seek(0x88, SeekOrigin.Begin); // next one +20 uint width = file.ReadUInt16(); @@ -49,7 +54,7 @@ namespace GameRes.Formats.Kid return null; file.Seek(real_sign, SeekOrigin.Begin); // usually 0x14 - if ((file.ReadUInt16() & 0x7FFF) != fstart) + if ((file.ReadUInt16() & 0x3FFF) != fstart) { return null; } @@ -105,6 +110,11 @@ namespace GameRes.Formats.Kid } // uint dx = dy * 32; + if (bpp == 8) //PSP format + { + dy = 16; + sliced = true; + } return new BipImageMetaData { @@ -113,6 +123,7 @@ namespace GameRes.Formats.Kid BlockSize = dy, Sliced = sliced, Multi = multi, + BPP = bpp, }; } public override ImageData Read(IBinaryStream file, ImageMetaData info) @@ -120,17 +131,19 @@ namespace GameRes.Formats.Kid if (info == null) throw new NotSupportedException(string.Format("Not BIP texture format.")); var bipheader = (BipImageMetaData)info; + + byte m_bpp = (byte)(bipheader.BPP / 8); file.Seek(0x10, SeekOrigin.Begin); uint fstart = file.ReadUInt16(); // usually 0x100 file.Seek(fstart, SeekOrigin.Begin); - byte[] pixels = new byte[bipheader.iWidth * bipheader.iHeight * 4]; + byte[] pixels = new byte[bipheader.iWidth * bipheader.iHeight * m_bpp]; uint dy = bipheader.BlockSize; uint dx = dy * 32; - if (bipheader.Sliced) + if (bipheader.Sliced && m_bpp == 4) { long dwidth = ((bipheader.iWidth + (dy - 2) - 1) / (dy - 2)) * dy; long dheight = ((bipheader.iHeight + (dy - 2) - 1) / (dy - 2)) * dy; - long focus_H = (dwidth* dheight + dx - 1) / dx; + long focus_H = (dwidth * dheight + dx - 1) / dx; long focus_T = (focus_H + dy - 1) / dy; for (int t = 0; t < focus_T; t++) @@ -139,7 +152,7 @@ namespace GameRes.Formats.Kid { for (int x = 0; x < dx; x++) { - var pixel = file.ReadBytes(4); //RGBA with wrong A + var pixel = file.ReadBytes(m_bpp); //RGBA with wrong A long i2x = x + t * dx; long i3t = i2x / dwidth; long i3x = i2x - i3t * dwidth; @@ -147,7 +160,7 @@ namespace GameRes.Formats.Kid long i4x = i3x - i3x / dy * dy + i3x / dy * (dy - 2); if (i3x >= dwidth || i4x >= bipheader.iWidth || i3y >= bipheader.iHeight) continue; - long target = (i4x + i3y * bipheader.iWidth) * 4; + long target = (i4x + i3y * bipheader.iWidth) * m_bpp; //BGRA pixels[target] = pixel[2]; pixels[target + 1] = pixel[1]; @@ -160,7 +173,36 @@ namespace GameRes.Formats.Kid } } } - else + else if(bipheader.Sliced && m_bpp == 1) + { + long dwidth = ((bipheader.iWidth + (dy - 1) - 1) / (dy - 1)) * dy; + long dheight = ((bipheader.iHeight + (dy - 1) - 1) / (dy - 1)) * dy; + long focus_H = (dwidth * dheight + dx - 1) / dx; + long focus_T = (focus_H + dy - 1) / dy; + + for (int t = 0; t < focus_T; t++) + { + for (int y = 0; y < dy; y++) + { + for (int x = 0; x < dx; x++) + { + var pixel = file.ReadUInt8(); + var dytemp = dy * 2; + long i2x = x + (t >> 1) * dx; + long i3t = i2x / dwidth; + long i3x = i2x - i3t * dwidth; + long i3y = i3t * (dytemp - 2) + y + (t % 2) * dy - 1; + long i4x = i3x - i3x / dytemp * dytemp + i3x / dytemp * (dytemp - 2) - 1; + if (i3x >= dwidth || i4x >= bipheader.iWidth || i3y >= bipheader.iHeight || i4x < 0 || i3y < 0) + continue; + long target = i4x + i3y * bipheader.iWidth; + + pixels[target] = pixel; + } + } + } + } + else //if(!bipheader.Sliced) { long focus_H = (bipheader.iWidth * bipheader.iHeight + dx - 1) / dx; long focus_T = (focus_H + dy - 1) / dy; @@ -170,27 +212,45 @@ namespace GameRes.Formats.Kid { for (int x = 0; x < dx; x++) { - var pixel = file.ReadBytes(4); //RGBA with wrong A + var pixel = file.ReadBytes(m_bpp); //RGBA with wrong A long i2x = x + t * dx; long i3t = i2x / bipheader.iWidth; long i3x = i2x - i3t * bipheader.iWidth; long i3y = i3t * dy + y; if (i3x >= bipheader.iWidth || i3y >= bipheader.iHeight) continue; - long target = (i3x + i3y * bipheader.iWidth) * 4; - //BGRA - pixels[target] = pixel[2]; - pixels[target + 1] = pixel[1]; - pixels[target + 2] = pixel[0]; - if (pixel[3] >= byte.MaxValue / 2) - pixels[target + 3] = byte.MaxValue; + long target = (i3x + i3y * bipheader.iWidth) * m_bpp; + if (m_bpp == 4) + { + //BGRA + pixels[target] = pixel[2]; + pixels[target + 1] = pixel[1]; + pixels[target + 2] = pixel[0]; + if (pixel[3] >= byte.MaxValue / 2) + pixels[target + 3] = byte.MaxValue; + else + pixels[target + 3] = (byte)(pixel[3] << 1); + } else - pixels[target + 3] = (byte)(pixel[3] << 1); + { + pixels[target] = pixel[0]; + } } } } } - return ImageData.Create(info, PixelFormats.Bgra32, null, pixels); ; + + if (m_bpp == 1) + { + file.Seek(0x0C, SeekOrigin.Begin); + uint palettestart = file.ReadUInt16(); // usually 0x100 + file.Seek(palettestart, SeekOrigin.Begin); + var color_map = ImageFormat.ReadColorMap(file.AsStream, 256, PaletteFormat.RgbA); + BitmapPalette Palette = new BitmapPalette(color_map); + + return ImageData.Create(info, PixelFormats.Indexed8, Palette, pixels); + } + return ImageData.Create(info, PixelFormats.Bgra32, null, pixels); } public override void Write(Stream file, ImageData image) {