Merge pull request #83 from Manicsteiner/feat_bip256

Add support of 256 color BIP
This commit is contained in:
Crsky
2025-03-12 14:18:04 +08:00
committed by GitHub

View File

@@ -1,11 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO; using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Media3D; using System.Windows.Media.Imaging;
namespace GameRes.Formats.Kid namespace GameRes.Formats.Kid
{ {
@@ -38,9 +34,18 @@ namespace GameRes.Formats.Kid
return null; // throw new NotSupportedException(string.Format("BIP Chara format not supported.")); 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); file.Seek(0x10, SeekOrigin.Begin);
uint fstart = file.ReadUInt16(); // usually 0x100 uint fstart = file.ReadUInt16(); // usually 0x100
byte bpp = 32;
if (fstart - palettestart == 1024)
{
bpp = 8;
}
// Non-Sequential read // Non-Sequential read
file.Seek(0x88, SeekOrigin.Begin); // next one +20 file.Seek(0x88, SeekOrigin.Begin); // next one +20
uint width = file.ReadUInt16(); uint width = file.ReadUInt16();
@@ -49,7 +54,7 @@ namespace GameRes.Formats.Kid
return null; return null;
file.Seek(real_sign, SeekOrigin.Begin); // usually 0x14 file.Seek(real_sign, SeekOrigin.Begin); // usually 0x14
if ((file.ReadUInt16() & 0x7FFF) != fstart) if ((file.ReadUInt16() & 0x3FFF) != fstart)
{ {
return null; return null;
} }
@@ -105,6 +110,21 @@ namespace GameRes.Formats.Kid
} }
// uint dx = dy * 32; // uint dx = dy * 32;
if (bpp == 8) //256C format
{
sliced = true;
oversize = (double)width * height / (file.Length - fstart);
if (oversize > 0.85 || width == 480 || height == 360) // PSP format force 16
{
dy = 16;
// standard: 0.8789 large: 0.7418
}
else
{
dy = 32;
// standard: 0.7817 large: 0.8333
}
}
return new BipImageMetaData return new BipImageMetaData
{ {
@@ -113,6 +133,7 @@ namespace GameRes.Formats.Kid
BlockSize = dy, BlockSize = dy,
Sliced = sliced, Sliced = sliced,
Multi = multi, Multi = multi,
BPP = bpp,
}; };
} }
public override ImageData Read(IBinaryStream file, ImageMetaData info) public override ImageData Read(IBinaryStream file, ImageMetaData info)
@@ -120,26 +141,62 @@ namespace GameRes.Formats.Kid
if (info == null) if (info == null)
throw new NotSupportedException(string.Format("Not BIP texture format.")); throw new NotSupportedException(string.Format("Not BIP texture format."));
var bipheader = (BipImageMetaData)info; var bipheader = (BipImageMetaData)info;
byte m_bpp = (byte)(bipheader.BPP / 8);
file.Seek(0x10, SeekOrigin.Begin); file.Seek(0x10, SeekOrigin.Begin);
uint fstart = file.ReadUInt16(); // usually 0x100 uint fstart = file.ReadUInt16(); // usually 0x100
file.Seek(fstart, SeekOrigin.Begin); 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 dy = bipheader.BlockSize;
uint dx = dy * 32; uint dx = dy * 32;
if (bipheader.Sliced)
if (bipheader.Sliced && m_bpp == 1 && dy == 16)
{ {
long dwidth = ((bipheader.iWidth + (dy - 2) - 1) / (dy - 2)) * dy; long dwidth = ((bipheader.iWidth + (dy * 2 - 2) - 1) / (dy * 2 - 2)) * dy * 2;
long dheight = ((bipheader.iHeight + (dy - 2) - 1) / (dy - 2)) * dy; long dheight = ((bipheader.iHeight + (dy * 2 - 2) - 1) / (dy * 2 - 2)) * dy * 2;
long focus_H = (dwidth* dheight + dx - 1) / dx; long focus_H = (dwidth * dheight + dx - 1) / dx;
long focus_T = (focus_H + dy - 1) / dy; long focus_T = (focus_H + dy - 1) / dy;
if (focus_T % 2 == 1)
{
focus_T++;
}
for (int t = 0; t < focus_T; t++) for (int t = 0; t < focus_T; t++)
{ {
for(int y = 0; y < dy; y++) for (int y = 0; y < dy; y++)
{ {
for (int x = 0; x < dx; x++) for (int x = 0; x < dx; x++)
{ {
var pixel = file.ReadBytes(4); //RGBA with wrong A 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/* && m_bpp == 4 or bpp=1 dy=32*/)
{
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_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.ReadBytes(m_bpp); //RGBA with wrong A
long i2x = x + t * dx; long i2x = x + t * dx;
long i3t = i2x / dwidth; long i3t = i2x / dwidth;
long i3x = i2x - i3t * dwidth; long i3x = i2x - i3t * dwidth;
@@ -147,20 +204,27 @@ namespace GameRes.Formats.Kid
long i4x = i3x - i3x / dy * dy + i3x / dy * (dy - 2); long i4x = i3x - i3x / dy * dy + i3x / dy * (dy - 2);
if (i3x >= dwidth || i4x >= bipheader.iWidth || i3y >= bipheader.iHeight) if (i3x >= dwidth || i4x >= bipheader.iWidth || i3y >= bipheader.iHeight)
continue; continue;
long target = (i4x + i3y * bipheader.iWidth) * 4; long target = (i4x + i3y * bipheader.iWidth) * m_bpp;
//BGRA if(m_bpp == 4)
pixels[target] = pixel[2]; {
pixels[target + 1] = pixel[1]; //BGRA
pixels[target + 2] = pixel[0]; pixels[target] = pixel[2];
if (pixel[3] >= byte.MaxValue / 2) pixels[target + 1] = pixel[1];
pixels[target + 3] = byte.MaxValue; 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 else
pixels[target + 3] = (byte)(pixel[3] << 1); {
pixels[target] = pixel[0];
}
} }
} }
} }
} }
else else //if(!bipheader.Sliced)
{ {
long focus_H = (bipheader.iWidth * bipheader.iHeight + dx - 1) / dx; long focus_H = (bipheader.iWidth * bipheader.iHeight + dx - 1) / dx;
long focus_T = (focus_H + dy - 1) / dy; long focus_T = (focus_H + dy - 1) / dy;
@@ -170,27 +234,45 @@ namespace GameRes.Formats.Kid
{ {
for (int x = 0; x < dx; x++) 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 i2x = x + t * dx;
long i3t = i2x / bipheader.iWidth; long i3t = i2x / bipheader.iWidth;
long i3x = i2x - i3t * bipheader.iWidth; long i3x = i2x - i3t * bipheader.iWidth;
long i3y = i3t * dy + y; long i3y = i3t * dy + y;
if (i3x >= bipheader.iWidth || i3y >= bipheader.iHeight) if (i3x >= bipheader.iWidth || i3y >= bipheader.iHeight)
continue; continue;
long target = (i3x + i3y * bipheader.iWidth) * 4; long target = (i3x + i3y * bipheader.iWidth) * m_bpp;
//BGRA if (m_bpp == 4)
pixels[target] = pixel[2]; {
pixels[target + 1] = pixel[1]; //BGRA
pixels[target + 2] = pixel[0]; pixels[target] = pixel[2];
if (pixel[3] >= byte.MaxValue / 2) pixels[target + 1] = pixel[1];
pixels[target + 3] = byte.MaxValue; 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 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, dy == 16 ? PaletteFormat.RgbA : PaletteFormat.RgbA7);
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) public override void Write(Stream file, ImageData image)
{ {