implemented 16bpp LIM images.

This commit is contained in:
morkt 2016-04-15 12:16:09 +04:00
parent dee61a2929
commit 37da6b588e
2 changed files with 150 additions and 26 deletions

View File

@ -479,10 +479,12 @@ namespace GameRes.Formats.Liar
int flag = stream.ReadByte() & 0xF;
if (flag != 2 && flag != 3)
return null;
stream.Seek (5, SeekOrigin.Current);
stream.ReadByte();
using (var file = new ArcView.Reader (stream))
{
var meta = new ImageMetaData { BPP = 32 };
int bpp = 0x10 == file.ReadUInt16() ? 16 : 32;
var meta = new ImageMetaData { BPP = bpp };
file.ReadUInt16();
meta.Width = file.ReadUInt32();
meta.Height = file.ReadUInt32();
return meta;
@ -512,16 +514,24 @@ namespace GameRes.Formats.Liar
byte[] m_image;
int m_width;
int m_height;
int m_bpp;
public byte[] Data { get { return m_image; } }
public PixelFormat Format { get { return PixelFormats.Bgra32; } }
public PixelFormat Format { get; private set; }
public Reader (Stream file, ImageMetaData info)
{
m_input = new ArcView.Reader (file);
m_width = (int)info.Width;
m_height = (int)info.Height;
m_image = new byte[m_width*m_height*4];
m_bpp = info.BPP;
if (32 == m_bpp)
Format = PixelFormats.Bgra32;
else if (16 == m_bpp)
Format = PixelFormats.Bgr565;
else
throw new InvalidFormatException();
m_image = new byte[m_width*m_height*m_bpp/8];
}
int m_remaining;
@ -529,25 +539,19 @@ namespace GameRes.Formats.Liar
int m_bits;
public void Unpack ()
{
if (32 == m_bpp)
Unpack32bpp();
else
Unpack16bpp();
}
void Unpack32bpp ()
{
byte mask = 0xFF;
for (int i = 3; i >= 0; --i)
{
int channel_size = m_input.ReadInt32();
if (null == m_output)
m_output = new byte[channel_size];
else if (channel_size != m_output.Length)
throw new InvalidFormatException();
m_remaining = m_input.ReadInt32();
int index_size = m_input.ReadUInt16();
if (null == m_index || index_size > m_index.Length)
m_index = new byte[index_size];
m_input.ReadInt16(); // ignored
if (m_index.Length != m_input.Read (m_index, 0, m_index.Length))
throw new InvalidFormatException ("Unexpected end of file");
UnpackChannel();
UnpackChannel (3);
int src = 0;
for (int p = i; p < m_image.Length; p += 4)
{
@ -557,13 +561,117 @@ namespace GameRes.Formats.Liar
}
}
void UnpackChannel ()
void Unpack16bpp ()
{
int image_size = m_input.ReadInt32();
m_output = m_image;
m_remaining = m_input.ReadInt32();
int index_size = m_input.ReadUInt16() * 2;
if (null == m_index || index_size > m_index.Length)
m_index = new byte[index_size];
m_input.ReadInt16(); // ignored
if (index_size != m_input.Read (m_index, 0, index_size))
throw new InvalidFormatException ("Unexpected end of file");
int card;
if (index_size > 8192)
{
m_index_threshold = 14;
m_index_length_limit = 16;
card = 4;
}
else
{
m_index_threshold = 6;
m_index_length_limit = 12;
card = 3;
}
m_current = 0;
int dst = 0;
while (dst < m_output.Length)
{
int bits = GetBits (3);
int bits = GetBits (card);
if (-1 == bits)
break;
if (0 != bits)
{
int index = GetIndex (bits);
if (index < 0)
break;
if (dst + 1 >= m_output.Length)
break;
m_output[dst++] = m_index[index*2];
m_output[dst++] = m_index[index*2+1];
}
else
{
int count = GetBits (4);
if (-1 == count)
break;
bits = GetBits (card);
if (-1 == bits)
break;
int index = GetIndex (bits);
if (-1 == index)
break;
count += 2;
index *= 2;
for (int i = 0; i < count; i++)
{
if (dst + 1 >= m_output.Length)
return;
m_output[dst++] = m_index[index];
m_output[dst++] = m_index[index+1];
}
}
}
if (m_input.BaseStream.Position < m_input.BaseStream.Length)
{
m_output = null;
UnpackChannel (3);
var pixels = new byte[m_width*m_height*4];
int alpha_src = 0;
dst = 0;
for (int i = 0; i < m_image.Length; i += 2)
{
int color = LittleEndian.ToUInt16 (m_image, i);
pixels[dst++] = (byte)((color & 0x001F) * 0xFF / 0x1F);
pixels[dst++] = (byte)((color & 0x07E0) * 0xFF / 0x7E0);
pixels[dst++] = (byte)((color & 0xF800) * 0xFF / 0xF800);
pixels[dst++] = (byte)~m_output[alpha_src++];
}
m_image = pixels;
Format = PixelFormats.Bgra32;
}
}
void UnpackChannel (int card)
{
m_index_threshold = 6;
m_index_length_limit = 12;
int channel_size = m_input.ReadInt32();
if (null == m_output || m_output.Length < channel_size)
m_output = new byte[channel_size];
m_remaining = m_input.ReadInt32();
int index_size = m_input.ReadUInt16();
if (null == m_index || index_size > m_index.Length)
m_index = new byte[index_size];
m_input.ReadInt16(); // ignored
if (index_size != m_input.Read (m_index, 0, index_size))
throw new InvalidFormatException ("Unexpected end of file");
m_current = 0;
int dst = 0;
while (dst < m_output.Length)
{
int bits = GetBits (card);
if (-1 == bits)
break;
@ -583,7 +691,7 @@ namespace GameRes.Formats.Liar
if (-1 == count)
break;
bits = GetBits (3);
bits = GetBits (card);
if (-1 == bits)
break;
@ -608,7 +716,10 @@ namespace GameRes.Formats.Liar
{
if (0 == m_current)
{
if (0 == m_remaining)
return 0;
m_bits = m_input.ReadByte();
--m_remaining;
m_current = 8;
}
v <<= 1;
@ -620,9 +731,12 @@ namespace GameRes.Formats.Liar
return v;
}
int m_index_threshold;
int m_index_length_limit;
private int GetIndex (int bits)
{
if (bits < 7)
if (bits <= m_index_threshold)
{
if (0 == bits)
return -1;
@ -630,7 +744,7 @@ namespace GameRes.Formats.Liar
return GetBits (1);
return (1 << bits) | GetBits (bits);
}
for (int i = 6; i < 12; ++i)
for (int i = m_index_threshold; i < m_index_length_limit; ++i)
{
bits = GetBits (1);
if (-1 == bits)

View File

@ -187,14 +187,16 @@ Yume Miru Kusuri<br/>
</td></tr>
<tr><td>*.wip<br/>*.msk<br/>*.mos</td><td><tt>WIPF</tt></td><td>No</td></tr>
<tr><td>*.pna</td><td><tt>PNAP</tt></td><td>No</td></tr>
<tr class="odd"><td>*.xfl</td><td><tt>LB</tt></td><td>Yes</td><td rowspan="3">Liar-soft</td><td rowspan="3">
<tr class="odd"><td>*.xfl</td><td><tt>LB</tt></td><td>Yes</td><td rowspan="4">Liar-soft</td><td rowspan="4">
Angel Bullet<br/>
Fairytale Requiem<br/>
Love Negotiator<br/>
Sekien no Inganock<br/>
Shikkoku no Sharnoth<br/>
</td></tr>
<tr class="odd"><td>*.lwg</td><td><tt>LG</tt></td><td>No</td></tr>
<tr class="odd"><td>*.wcg</td><td><tt>WGq</tt></td><td>Yes</td></tr>
<tr class="odd"><td>*.lim</td><td><tt>LM</tt></td><td>No</td></tr>
<tr><td>*.xp3</td><td><tt>XP3</tt></td><td>Yes</td><td rowspan="2">KiriKiri</td><td rowspan="2">
Altered Pink ~Tokumu Sentai Duel Ranger~<br/>
Aozora Gakko no Sensei-kun<br/>
@ -221,6 +223,7 @@ Nuki Doki!<br/>
Okiba ga Nai!<br/>
Oku-sama wa Moto Yariman<br/>
Ore no Saimin Fantasia<br/>
RGH ~Koi to Hero to Gakuen to~<br/>
Riding Incubus<br/>
Seirei Tenshou<br/>
Se-kirara<br/>
@ -330,6 +333,7 @@ Jokyoushi wo Kurau<br/>
Lovers Collection<br/>
Nachtmusik<br/>
Nachtmusik Another<br/>
Oto☆Puri<br/>
Samayou Mitama ni Yasuragi no Toki wo<br/>
Time Trouble ~Marie ni Kubikkake~<br/>
</td></tr>
@ -431,6 +435,7 @@ Hissatsu Chikannin II<br/>
Ryoujoku Gojuusou<br/>
Tokumei Sentai Sirenger<br/>
Tokumei Sentai Yuzu Ranger<br/>
Zetsuboushi<br/>
</td></tr>
<tr class="odd"><td>*.cwp</td><td><tt>CWDP</tt></td><td>Yes</td></tr>
<tr class="odd"><td>*.cwd</td><td><tt>cwd</tt></td><td>No</td></tr>
@ -468,6 +473,7 @@ Dies irae ~Amantes amentes~<br/>
Kajiri Kamui Kagura<br/>
Paradise Lost<br/>
Sakashiki Hito ni Miru Kokoro<br/>
Tenmon Dokei no Aria<br/>
Zettai Meikyuu Grimm<br/>
</td></tr>
<tr class="odd"><td>*.mgf</td><td><tt>MalieGF</tt></td><td>Yes</td></tr>
@ -536,7 +542,9 @@ Yami no Koe Zero<br/>
<tr><td>*.vaw<br/>*.wgq</td><td><tt>IF PACKTYPE==</tt><br/><tt>OGG</tt></td><td>No</td></tr>
<tr class="odd"><td>*.aos</td><td>-</td><td>No</td><td rowspan="2">LiLiM</td><td rowspan="2">
Answer Dead<br/>
Houou Senki Maimu<br/>
Kango Sentai Nurse Ranger<br/>
Megami Taisen<br/>
</td></tr>
<tr class="odd"><td>*.abm</td><td><tt>BM</tt></td><td>No</td></tr>
<tr><td>*.arc<br/>*.xarc<br/>*.bin</td><td><tt>MIKO</tt><br/><tt>KOTORI</tt><br/><tt>XARC</tt></td><td>No</td><td rowspan="2">Xuse<br/>ETERNAL</td><td rowspan="2">
@ -549,6 +557,7 @@ Seinarukana -The Spirit of Eternity Sword 2-<br/>
<tr><td>*.wag<br/>*.4ag<br/>*.004</td><td><tt>WAG@</tt><br/><tt>GAF4</tt></td><td>No</td></tr>
<tr class="odd"><td>*.ykc</td><td><tt>YKC001</tt></td><td>Yes</td><td rowspan="2">Yuka</td><td rowspan="2">
Aozora no Mieru Oka<br/>
HoneyComing<br/>
PriministAr<br/>
SuGirly Wish<br/>
_summer<br/>
@ -708,7 +717,7 @@ Level Justice<br/>
</td></tr>
<tr><td>*.iph</td><td><tt>RIFF....IPH fmt</tt></td><td>No</td></tr>
<tr><td>*.aog</td><td><tt>AoiOgg</tt></td><td>No</td></tr>
<tr><td>*.box</td><td><tt>AOIBX10</tt></td><td>No</td></tr>
<tr><td>*.box</td><td><tt>AOIBX10</tt><br/><tt>AOIBOX7</tt></td><td>No</td></tr>
<tr class="odd"><td>*.gd+*.dll</td><td>-</td><td>No</td><td>Xuse</td><td>
Eien no Aselia -The Spirit of Eternity Sword-
</td></tr>
@ -757,6 +766,7 @@ Angenehm Platz -Kleiner Garten Sie Erstellen-<br/>
</td></tr>
<tr><td>*.eme</td><td><tt>RREDATA</tt></td><td>No</td><td>Emon Engine</td><td>
Ase Nure Shoujo Misaki "Anata no Nioi de Icchau!"<br/>
Hitomi no Rakuin ~Inbaku no Mesu Dorei~<br/>
</td></tr>
<tr class="odd"><td>*.grp</td><td>-</td><td>No</td><td>Ankh</td><td>
Mozu<br/>