(PSB): support "icon" entries and RL compression.

This commit is contained in:
morkt 2017-02-13 20:03:46 +04:00
parent dc1647c5bf
commit f6f989dd2f

View File

@ -246,26 +246,64 @@ namespace GameRes.Formats.Emote
var item_value = item.Value as IDictionary; var item_value = item.Value as IDictionary;
if (null == item_value) if (null == item_value)
continue; continue;
var texture = item_value["texture"] as IDictionary; if (item_value.Contains ("texture"))
if (null == texture) {
continue; AddTextureEntry (dir, item.Key, item_value["texture"] as IDictionary);
var pixel = texture["pixel"] as EmChunk; }
else if (item_value.Contains ("icon"))
{
AddIconEntry (dir, item.Key, item_value["icon"] as IDictionary);
}
}
return dir;
}
void AddTextureEntry (List<Entry> dir, object name, IDictionary texture)
{
if (null == texture)
return;
var pixel = texture["pixel"] as EmChunk;
if (null == pixel)
return;
var entry = new TexEntry {
Name = name.ToString(),
Type = "image",
Offset = DataOffset + pixel.Offset,
Size = (uint)pixel.Length,
TexType = texture["type"].ToString(),
Width = Convert.ToInt32 (texture["width"]),
Height = Convert.ToInt32 (texture["height"]),
TruncatedWidth = Convert.ToInt32 (texture["truncated_width"]),
TruncatedHeight = Convert.ToInt32 (texture["truncated_height"]),
};
dir.Add (entry);
}
void AddIconEntry (List<Entry> dir, object name, IDictionary icon_list)
{
if (null == icon_list)
return;
foreach (DictionaryEntry icon in icon_list)
{
var layer = icon.Value as IDictionary;
var pixel = layer["pixel"] as EmChunk;
if (null == pixel) if (null == pixel)
continue; continue;
var entry = new TexEntry { var entry = new TexEntry {
Name = item.Key.ToString(), Name = name.ToString()+'#'+icon.Key.ToString(),
Type = "image", Type = "image",
Offset = DataOffset + pixel.Offset, Offset = DataOffset + pixel.Offset,
Size = (uint)pixel.Length, Size = (uint)pixel.Length,
TexType = texture["type"].ToString(), Width = Convert.ToInt32 (layer["width"]),
Width = Convert.ToInt32 (texture["width"]), Height = Convert.ToInt32 (layer["height"]),
Height = Convert.ToInt32 (texture["height"]), OffsetX = Convert.ToInt32 (layer["originX"]),
TruncatedWidth = Convert.ToInt32 (texture["truncated_width"]), OffsetY = Convert.ToInt32 (layer["originY"]),
TruncatedHeight = Convert.ToInt32 (texture["truncated_height"]), TexType = layer.Contains ("compress") ? layer["compress"].ToString() : "RGBA8",
}; };
entry.TruncatedWidth = entry.Width;
entry.TruncatedHeight = entry.Height;
dir.Add (entry); dir.Add (entry);
} }
return dir;
} }
int m_names; int m_names;
@ -651,6 +689,8 @@ namespace GameRes.Formats.Emote
ReadA8L8 (pixels, stride); ReadA8L8 (pixels, stride);
else if ("RGBA4444" == m_info.TexType) else if ("RGBA4444" == m_info.TexType)
ReadRgba4444 (pixels, stride); ReadRgba4444 (pixels, stride);
else if ("RL" == m_info.TexType)
ReadRle (pixels, stride);
else else
throw new NotImplementedException (string.Format ("PSB texture format '{0}' not implemented", m_info.TexType)); throw new NotImplementedException (string.Format ("PSB texture format '{0}' not implemented", m_info.TexType));
return ImageData.Create (m_info, PixelFormats.Bgra32, null, pixels, stride); return ImageData.Create (m_info, PixelFormats.Bgra32, null, pixels, stride);
@ -734,5 +774,28 @@ namespace GameRes.Formats.Emote
} }
} }
} }
void ReadRle (byte[] output, int dst_stride)
{
const int pixel_size = 4;
m_input.Position = 0;
int dst = 0;
while (dst < output.Length)
{
int count = m_input.ReadUInt8();
if (0 == (count & 0x80))
{
count = pixel_size * (count + 1);
dst += m_input.Read (output, dst, count);
}
else
{
count = pixel_size * ((count & 0x7F) + 3);
m_input.Read (output, dst, pixel_size);
Binary.CopyOverlapped (output, dst, dst+pixel_size, count-pixel_size);
dst += count;
}
}
}
} }
} }