mirror of
https://github.com/crskycode/GARbro.git
synced 2026-07-08 01:30:18 +08:00
(Pb3Reader): moved common methods to separate class.
This commit is contained in:
@@ -33,13 +33,17 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace GameRes.Formats.Purple
|
namespace GameRes.Formats.Purple
|
||||||
{
|
{
|
||||||
internal class Pb3MetaData : ImageMetaData
|
internal class PbMetaData : ImageMetaData
|
||||||
{
|
{
|
||||||
public int Type;
|
public int Type;
|
||||||
public int SubType;
|
|
||||||
public int InputSize;
|
public int InputSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class Pb3MetaData : PbMetaData
|
||||||
|
{
|
||||||
|
public int SubType;
|
||||||
|
}
|
||||||
|
|
||||||
[Export(typeof(ImageFormat))]
|
[Export(typeof(ImageFormat))]
|
||||||
public class Pb3Format : ImageFormat
|
public class Pb3Format : ImageFormat
|
||||||
{
|
{
|
||||||
@@ -81,23 +85,119 @@ namespace GameRes.Formats.Purple
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class Pb3Reader
|
internal class PbReaderBase
|
||||||
{
|
{
|
||||||
byte[] m_input;
|
protected PbMetaData m_info;
|
||||||
Pb3MetaData m_info;
|
protected byte[] m_input;
|
||||||
int m_channels;
|
protected byte[] m_output;
|
||||||
int m_stride;
|
protected byte[] m_lzss_frame = new byte[0x800];
|
||||||
byte[] m_output;
|
protected int m_stride;
|
||||||
byte[] m_lzss_frame;
|
|
||||||
|
|
||||||
public PixelFormat Format { get; private set; }
|
protected PbReaderBase (PbMetaData info)
|
||||||
|
{
|
||||||
|
m_info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PixelFormat Format { get; protected set; }
|
||||||
public byte[] Data { get { return m_output; } }
|
public byte[] Data { get { return m_output; } }
|
||||||
|
|
||||||
public Pb3Reader (Stream input, Pb3MetaData info)
|
internal void LzssResetFrame ()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 0x7DE; ++i)
|
||||||
|
m_lzss_frame[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void LzssUnpack (int bit_src, int data_src, byte[] output, int output_size)
|
||||||
|
{
|
||||||
|
int dst = 0;
|
||||||
|
int bit_mask = 0x80;
|
||||||
|
int frame_offset = 0x7DE;
|
||||||
|
while (dst < output_size)
|
||||||
|
{
|
||||||
|
if (0 == bit_mask)
|
||||||
|
{
|
||||||
|
bit_mask = 0x80;
|
||||||
|
++bit_src;
|
||||||
|
}
|
||||||
|
if (0 != (bit_mask & m_input[bit_src]))
|
||||||
|
{
|
||||||
|
int v = LittleEndian.ToUInt16 (m_input, data_src);
|
||||||
|
data_src += 2;
|
||||||
|
int count = (v & 0x1F) + 3;
|
||||||
|
int offset = v >> 5;
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
byte b = m_lzss_frame[(i + offset) & 0x7FF];
|
||||||
|
output[dst++] = b;
|
||||||
|
m_lzss_frame[frame_offset++] = b;
|
||||||
|
frame_offset &= 0x7FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byte b = m_input[data_src++];
|
||||||
|
output[dst++] = b;
|
||||||
|
m_lzss_frame[frame_offset++] = b;
|
||||||
|
frame_offset &= 0x7FF;
|
||||||
|
}
|
||||||
|
bit_mask >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void UnpackJbp (int jbp_pos, int alpha_pos)
|
||||||
|
{
|
||||||
|
var jbp = new JbpReader (m_input, jbp_pos);
|
||||||
|
m_output = jbp.Unpack();
|
||||||
|
if (m_stride != jbp.Stride)
|
||||||
|
{
|
||||||
|
int src_stride = jbp.Stride;
|
||||||
|
int src = src_stride;
|
||||||
|
int dst = m_stride;
|
||||||
|
for (uint y = 1; y < m_info.Height; ++y)
|
||||||
|
{
|
||||||
|
Buffer.BlockCopy (m_output, src, m_output, dst, m_stride);
|
||||||
|
src += src_stride;
|
||||||
|
dst += m_stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (32 == m_info.BPP && alpha_pos > 0)
|
||||||
|
{
|
||||||
|
int dst = 3;
|
||||||
|
int output_end = m_stride * (int)m_info.Height;
|
||||||
|
while (dst < output_end)
|
||||||
|
{
|
||||||
|
byte alpha = m_input[alpha_pos++];
|
||||||
|
if (0 != alpha && 0xFF != alpha)
|
||||||
|
{
|
||||||
|
m_output[dst] = alpha;
|
||||||
|
dst += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int count = m_input[alpha_pos++];
|
||||||
|
while (count --> 0)
|
||||||
|
{
|
||||||
|
m_output[dst] = alpha;
|
||||||
|
dst += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Format = PixelFormats.Bgr32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class Pb3Reader : PbReaderBase
|
||||||
|
{
|
||||||
|
int m_channels;
|
||||||
|
|
||||||
|
public Pb3Reader (Stream input, Pb3MetaData info) : base (info)
|
||||||
{
|
{
|
||||||
if (info.Type == 1 && info.SubType != 0x10)
|
if (info.Type == 1 && info.SubType != 0x10)
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
m_info = info;
|
|
||||||
if (3 == m_info.Type || 2 == m_info.Type)
|
if (3 == m_info.Type || 2 == m_info.Type)
|
||||||
m_input = new byte[input.Length];
|
m_input = new byte[input.Length];
|
||||||
else
|
else
|
||||||
@@ -106,7 +206,6 @@ namespace GameRes.Formats.Purple
|
|||||||
throw new EndOfStreamException();
|
throw new EndOfStreamException();
|
||||||
m_channels = m_info.BPP / 8;
|
m_channels = m_info.BPP / 8;
|
||||||
m_stride = 4 * (int)m_info.Width;
|
m_stride = 4 * (int)m_info.Width;
|
||||||
m_lzss_frame = new byte[0x800];
|
|
||||||
Format = m_channels < 4 ? PixelFormats.Bgr32 : PixelFormats.Bgra32;
|
Format = m_channels < 4 ? PixelFormats.Bgr32 : PixelFormats.Bgra32;
|
||||||
// output array created by unpack methods as needed.
|
// output array created by unpack methods as needed.
|
||||||
}
|
}
|
||||||
@@ -121,7 +220,7 @@ namespace GameRes.Formats.Purple
|
|||||||
case 8:
|
case 8:
|
||||||
case 6: UnpackV6(); break;
|
case 6: UnpackV6(); break;
|
||||||
case 2:
|
case 2:
|
||||||
case 3: UnpackV3(); break;
|
case 3: UnpackJbp (0x34, m_input.ToInt32 (0x2C)); break;
|
||||||
case 4:
|
case 4:
|
||||||
case 7: throw new NotSupportedException(string.Format ("PB3 v{0} images not supported", m_info.Type));
|
case 7: throw new NotSupportedException(string.Format ("PB3 v{0} images not supported", m_info.Type));
|
||||||
}
|
}
|
||||||
@@ -160,8 +259,7 @@ namespace GameRes.Formats.Purple
|
|||||||
channel_offset += LittleEndian.ToInt32 (m_input, data2 + 4*i);
|
channel_offset += LittleEndian.ToInt32 (m_input, data2 + 4*i);
|
||||||
int data_src = data2 + channel_offset;
|
int data_src = data2 + channel_offset;
|
||||||
|
|
||||||
for (int i = 0; i < 0x7DE; ++i)
|
LzssResetFrame();
|
||||||
m_lzss_frame[i] = 0;
|
|
||||||
LzssUnpack (bit_src, data_src, plane, channel_size);
|
LzssUnpack (bit_src, data_src, plane, channel_size);
|
||||||
|
|
||||||
if (0 == y_blocks || 0 == x_blocks)
|
if (0 == y_blocks || 0 == x_blocks)
|
||||||
@@ -222,52 +320,6 @@ namespace GameRes.Formats.Purple
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnpackV3 ()
|
|
||||||
{
|
|
||||||
var jbp = new JbpReader (m_input, 0x34);
|
|
||||||
m_output = jbp.Unpack();
|
|
||||||
if (m_stride != jbp.Stride)
|
|
||||||
{
|
|
||||||
int src_stride = jbp.Stride;
|
|
||||||
int src = src_stride;
|
|
||||||
int dst = m_stride;
|
|
||||||
for (uint y = 1; y < m_info.Height; ++y)
|
|
||||||
{
|
|
||||||
Buffer.BlockCopy (m_output, src, m_output, dst, m_stride);
|
|
||||||
src += src_stride;
|
|
||||||
dst += m_stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int alpha_pos = LittleEndian.ToInt32 (m_input, 0x2C);
|
|
||||||
if (32 == m_info.BPP && alpha_pos > 0)
|
|
||||||
{
|
|
||||||
int dst = 3;
|
|
||||||
int output_end = m_stride * (int)m_info.Height;
|
|
||||||
while (dst < output_end)
|
|
||||||
{
|
|
||||||
byte alpha = m_input[alpha_pos++];
|
|
||||||
if (0 != alpha && 0xFF != alpha)
|
|
||||||
{
|
|
||||||
m_output[dst] = alpha;
|
|
||||||
dst += 4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int count = m_input[alpha_pos++];
|
|
||||||
while (count --> 0)
|
|
||||||
{
|
|
||||||
m_output[dst] = alpha;
|
|
||||||
dst += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Format = PixelFormats.Bgr32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnpackV5 ()
|
void UnpackV5 ()
|
||||||
{
|
{
|
||||||
m_output = new byte[m_stride * (int)m_info.Height];
|
m_output = new byte[m_stride * (int)m_info.Height];
|
||||||
@@ -275,8 +327,7 @@ namespace GameRes.Formats.Purple
|
|||||||
{
|
{
|
||||||
int bit_src = 0x54 + LittleEndian.ToInt32 (m_input, 8 * i + 0x34);
|
int bit_src = 0x54 + LittleEndian.ToInt32 (m_input, 8 * i + 0x34);
|
||||||
int data_src = 0x54 + LittleEndian.ToInt32 (m_input, 8 * i + 0x38);
|
int data_src = 0x54 + LittleEndian.ToInt32 (m_input, 8 * i + 0x38);
|
||||||
for (int j = 0; j < 0x7DE; ++j)
|
LzssResetFrame();
|
||||||
m_lzss_frame[j] = 0;
|
|
||||||
int frame_offset = 0x7DE;
|
int frame_offset = 0x7DE;
|
||||||
byte accum = 0;
|
byte accum = 0;
|
||||||
int bit_mask = 128;
|
int bit_mask = 128;
|
||||||
@@ -357,43 +408,6 @@ namespace GameRes.Formats.Purple
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LzssUnpack (int bit_src, int data_src, byte[] output, int output_size)
|
|
||||||
{
|
|
||||||
int dst = 0;
|
|
||||||
int bit_mask = 0x80;
|
|
||||||
int frame_offset = 0x7DE;
|
|
||||||
while (dst < output_size)
|
|
||||||
{
|
|
||||||
if (0 == bit_mask)
|
|
||||||
{
|
|
||||||
bit_mask = 0x80;
|
|
||||||
++bit_src;
|
|
||||||
}
|
|
||||||
if (0 != (bit_mask & m_input[bit_src]))
|
|
||||||
{
|
|
||||||
int v = LittleEndian.ToUInt16 (m_input, data_src);
|
|
||||||
data_src += 2;
|
|
||||||
int count = (v & 0x1F) + 3;
|
|
||||||
int offset = v >> 5;
|
|
||||||
for (int i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
byte b = m_lzss_frame[(i + offset) & 0x7FF];
|
|
||||||
output[dst++] = b;
|
|
||||||
m_lzss_frame[frame_offset++] = b;
|
|
||||||
frame_offset &= 0x7FF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
byte b = m_input[data_src++];
|
|
||||||
output[dst++] = b;
|
|
||||||
m_lzss_frame[frame_offset++] = b;
|
|
||||||
frame_offset &= 0x7FF;
|
|
||||||
}
|
|
||||||
bit_mask >>= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BlendInput ()
|
void BlendInput ()
|
||||||
{
|
{
|
||||||
int bit_src = 0x20 + LittleEndian.ToInt32 (m_input, 0xC);
|
int bit_src = 0x20 + LittleEndian.ToInt32 (m_input, 0xC);
|
||||||
|
|||||||
Reference in New Issue
Block a user