mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-23 13:45:34 +08:00
(Pb3Reader): moved common methods to separate class.
This commit is contained in:
parent
a0a6f0024c
commit
6d3828a166
@ -33,13 +33,17 @@ using System.Collections.Generic;
|
||||
|
||||
namespace GameRes.Formats.Purple
|
||||
{
|
||||
internal class Pb3MetaData : ImageMetaData
|
||||
internal class PbMetaData : ImageMetaData
|
||||
{
|
||||
public int Type;
|
||||
public int SubType;
|
||||
public int InputSize;
|
||||
}
|
||||
|
||||
internal class Pb3MetaData : PbMetaData
|
||||
{
|
||||
public int SubType;
|
||||
}
|
||||
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class Pb3Format : ImageFormat
|
||||
{
|
||||
@ -81,23 +85,119 @@ namespace GameRes.Formats.Purple
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Pb3Reader
|
||||
internal class PbReaderBase
|
||||
{
|
||||
byte[] m_input;
|
||||
Pb3MetaData m_info;
|
||||
int m_channels;
|
||||
int m_stride;
|
||||
byte[] m_output;
|
||||
byte[] m_lzss_frame;
|
||||
protected PbMetaData m_info;
|
||||
protected byte[] m_input;
|
||||
protected byte[] m_output;
|
||||
protected byte[] m_lzss_frame = new byte[0x800];
|
||||
protected int m_stride;
|
||||
|
||||
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 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)
|
||||
throw new NotSupportedException();
|
||||
m_info = info;
|
||||
if (3 == m_info.Type || 2 == m_info.Type)
|
||||
m_input = new byte[input.Length];
|
||||
else
|
||||
@ -106,7 +206,6 @@ namespace GameRes.Formats.Purple
|
||||
throw new EndOfStreamException();
|
||||
m_channels = m_info.BPP / 8;
|
||||
m_stride = 4 * (int)m_info.Width;
|
||||
m_lzss_frame = new byte[0x800];
|
||||
Format = m_channels < 4 ? PixelFormats.Bgr32 : PixelFormats.Bgra32;
|
||||
// output array created by unpack methods as needed.
|
||||
}
|
||||
@ -121,7 +220,7 @@ namespace GameRes.Formats.Purple
|
||||
case 8:
|
||||
case 6: UnpackV6(); break;
|
||||
case 2:
|
||||
case 3: UnpackV3(); break;
|
||||
case 3: UnpackJbp (0x34, m_input.ToInt32 (0x2C)); break;
|
||||
case 4:
|
||||
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);
|
||||
int data_src = data2 + channel_offset;
|
||||
|
||||
for (int i = 0; i < 0x7DE; ++i)
|
||||
m_lzss_frame[i] = 0;
|
||||
LzssResetFrame();
|
||||
LzssUnpack (bit_src, data_src, plane, channel_size);
|
||||
|
||||
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 ()
|
||||
{
|
||||
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 data_src = 0x54 + LittleEndian.ToInt32 (m_input, 8 * i + 0x38);
|
||||
for (int j = 0; j < 0x7DE; ++j)
|
||||
m_lzss_frame[j] = 0;
|
||||
LzssResetFrame();
|
||||
int frame_offset = 0x7DE;
|
||||
byte accum = 0;
|
||||
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 ()
|
||||
{
|
||||
int bit_src = 0x20 + LittleEndian.ToInt32 (m_input, 0xC);
|
||||
|
Loading…
Reference in New Issue
Block a user