mirror of
https://github.com/crskycode/GARbro.git
synced 2024-12-25 04:14:13 +08:00
implemented PSB version 2 and "RGBA4444" textures.
This commit is contained in:
parent
eb1a913f1b
commit
16d433a29e
@ -132,7 +132,7 @@ namespace GameRes.Formats.Emote
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int Version { get { return m_version; } }
|
public int Version { get { return m_version; } }
|
||||||
public bool IsEncrypted { get { return 0 != (m_flags & 1); } }
|
public bool IsEncrypted { get { return 0 != (m_flags & 3); } }
|
||||||
public int DataOffset { get { return m_chunk_data; } }
|
public int DataOffset { get { return m_chunk_data; } }
|
||||||
|
|
||||||
public T GetRootKey<T> (string key)
|
public T GetRootKey<T> (string key)
|
||||||
@ -163,8 +163,9 @@ namespace GameRes.Formats.Emote
|
|||||||
if (Version < 2)
|
if (Version < 2)
|
||||||
throw new NotSupportedException ("Not supported PSB version");
|
throw new NotSupportedException ("Not supported PSB version");
|
||||||
m_name_map = ReadNames();
|
m_name_map = ReadNames();
|
||||||
// var dict = GetDict (m_root); // returns all metadata in a single dictionary
|
#if DEBUG
|
||||||
|
var dict = GetDict (m_root); // returns all metadata in a single dictionary
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,10 +219,10 @@ namespace GameRes.Formats.Emote
|
|||||||
if (m_version < 3)
|
if (m_version < 3)
|
||||||
m_flags = 2;
|
m_flags = 2;
|
||||||
|
|
||||||
var header = new byte[0x24];
|
var header = new byte[0x20];
|
||||||
m_input.Read (header, 0, header.Length);
|
m_input.Read (header, 0, header.Length);
|
||||||
if (0 != (m_flags & 1))
|
if (0 != (m_flags & 1))
|
||||||
Decrypt (header, 0, 0x24);
|
Decrypt (header, 0, 0x20);
|
||||||
|
|
||||||
m_names = LittleEndian.ToInt32 (header, 0x04);
|
m_names = LittleEndian.ToInt32 (header, 0x04);
|
||||||
m_strings = LittleEndian.ToInt32 (header, 0x08);
|
m_strings = LittleEndian.ToInt32 (header, 0x08);
|
||||||
@ -232,19 +233,23 @@ namespace GameRes.Formats.Emote
|
|||||||
m_root = LittleEndian.ToInt32 (header, 0x1C);
|
m_root = LittleEndian.ToInt32 (header, 0x1C);
|
||||||
|
|
||||||
int buffer_length = (int)m_input.BaseStream.Length;
|
int buffer_length = (int)m_input.BaseStream.Length;
|
||||||
if (!(m_names >= 0x28 && m_names < buffer_length
|
if (!(m_names >= 0x28 && m_names < m_chunk_data
|
||||||
&& m_strings >= 0x28 && m_strings < buffer_length
|
&& m_strings >= 0x28 && m_strings < m_chunk_data
|
||||||
&& m_strings_data >= 0x28 && m_strings_data < buffer_length
|
&& m_strings_data >= 0x28 && m_strings_data < m_chunk_data
|
||||||
&& m_chunk_offsets >= 0x28 && m_chunk_offsets < buffer_length
|
&& m_chunk_offsets >= 0x28 && m_chunk_offsets < m_chunk_data
|
||||||
&& m_chunk_lengths >= 0x28 && m_chunk_lengths < buffer_length
|
&& m_chunk_lengths >= 0x28 && m_chunk_lengths < m_chunk_data
|
||||||
&& m_chunk_data >= 0x28 && m_chunk_data < buffer_length
|
&& m_chunk_data >= 0x28 && m_chunk_data < buffer_length
|
||||||
&& m_root >= 0x28 && m_root < buffer_length))
|
&& m_root >= 0x28 && m_root < m_chunk_data))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (null == m_data || m_data.Length < m_chunk_data)
|
||||||
m_data = new byte[m_chunk_data];
|
m_data = new byte[m_chunk_data];
|
||||||
int data_pos = (int)m_input.BaseStream.Position;
|
int data_pos = (int)m_input.BaseStream.Position;
|
||||||
m_input.Read (m_data, data_pos, m_chunk_data-data_pos);
|
m_input.Read (m_data, data_pos, m_chunk_data-data_pos);
|
||||||
return true;
|
if (0 != (m_flags & 2))
|
||||||
|
Decrypt (m_data, m_names, m_chunk_offsets-m_names);
|
||||||
|
// root object is a dictionary
|
||||||
|
return 0x21 == m_data[m_root];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetKey (string name, int dict_offset, out int value_offset)
|
bool GetKey (string name, int dict_offset, out int value_offset)
|
||||||
@ -597,21 +602,52 @@ namespace GameRes.Formats.Emote
|
|||||||
public override ImageData Read (Stream stream, ImageMetaData info)
|
public override ImageData Read (Stream stream, ImageMetaData info)
|
||||||
{
|
{
|
||||||
var meta = (PsbTexMetaData)info;
|
var meta = (PsbTexMetaData)info;
|
||||||
if (meta.TexType != "RGBA8")
|
var pixels = new byte[meta.Width * meta.Height * 4];
|
||||||
|
if ("RGBA8" == meta.TexType)
|
||||||
|
ReadRgba8 (stream, meta, pixels);
|
||||||
|
else if ("RGBA4444" == meta.TexType)
|
||||||
|
ReadRgba4444 (stream, meta, pixels);
|
||||||
|
else
|
||||||
throw new NotImplementedException (string.Format ("PSB texture format '{0}' not implemented", meta.TexType));
|
throw new NotImplementedException (string.Format ("PSB texture format '{0}' not implemented", meta.TexType));
|
||||||
|
return ImageData.Create (info, PixelFormats.Bgra32, null, pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadRgba8 (Stream input, PsbTexMetaData meta, byte[] output)
|
||||||
|
{
|
||||||
int dst_stride = (int)meta.Width * 4;
|
int dst_stride = (int)meta.Width * 4;
|
||||||
var pixels = new byte[dst_stride * (int)meta.Height];
|
|
||||||
long next_row = meta.DataOffset;
|
long next_row = meta.DataOffset;
|
||||||
int src_stride = meta.FullWidth * 4;
|
int src_stride = meta.FullWidth * 4;
|
||||||
int dst = 0;
|
int dst = 0;
|
||||||
for (uint i = 0; i < meta.Height; ++i)
|
for (uint i = 0; i < meta.Height; ++i)
|
||||||
{
|
{
|
||||||
stream.Position = next_row;
|
input.Position = next_row;
|
||||||
stream.Read (pixels, dst, dst_stride);
|
input.Read (output, dst, dst_stride);
|
||||||
dst += dst_stride;
|
dst += dst_stride;
|
||||||
next_row += src_stride;
|
next_row += src_stride;
|
||||||
}
|
}
|
||||||
return ImageData.Create (info, PixelFormats.Bgra32, null, pixels);
|
}
|
||||||
|
|
||||||
|
void ReadRgba4444 (Stream input, PsbTexMetaData meta, byte[] output)
|
||||||
|
{
|
||||||
|
int dst_stride = (int)meta.Width * 4;
|
||||||
|
int src_stride = meta.FullWidth * 2;
|
||||||
|
int dst = 0;
|
||||||
|
var row = new byte[src_stride];
|
||||||
|
input.Position = meta.DataOffset;
|
||||||
|
for (uint i = 0; i < meta.Height; ++i)
|
||||||
|
{
|
||||||
|
input.Read (row, 0, src_stride);
|
||||||
|
int src = 0;
|
||||||
|
for (int x = 0; x < dst_stride; x += 4)
|
||||||
|
{
|
||||||
|
uint p = LittleEndian.ToUInt16 (row, src);
|
||||||
|
src += 2;
|
||||||
|
output[dst++] = (byte)((p & 0x000Fu) * 0xFFu / 0x000Fu);
|
||||||
|
output[dst++] = (byte)((p & 0x00F0u) * 0xFFu / 0x00F0u);
|
||||||
|
output[dst++] = (byte)((p & 0x0F00u) * 0xFFu / 0x0F00u);
|
||||||
|
output[dst++] = (byte)((p & 0xF000u) * 0xFFu / 0xF000u);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write (Stream file, ImageData image)
|
public override void Write (Stream file, ImageData image)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user