diff --git a/Legacy/Ucom/ImageUG.cs b/Legacy/Ucom/ImageUG.cs index 00cf6f9c..ce8a27b8 100644 --- a/Legacy/Ucom/ImageUG.cs +++ b/Legacy/Ucom/ImageUG.cs @@ -23,6 +23,7 @@ // IN THE SOFTWARE. // +using System; using System.ComponentModel.Composition; using System.IO; using System.Windows.Media; @@ -73,6 +74,9 @@ namespace GameRes.Formats.Ucom } } + /// + /// Same compression algorithm as the base, but scanlines are vertical + /// internal class UgReader : System98.GraBaseReader { public UgReader (IBinaryStream input, ImageMetaData info) : base (input, info) @@ -83,10 +87,136 @@ namespace GameRes.Formats.Ucom { m_input.Position = 8; var palette = ReadPalette(); - UnpackBits(); + m_input.Position = 0x28; + try + { + UnpackBitsInternal(); + } + catch (EndOfStreamException) + { + FlushBuffer(); + } return ImageData.Create (m_info, PixelFormats.Indexed4, palette, Pixels, Stride); } + void UnpackBitsInternal () + { + int height = m_info.iHeight; + int hTimes2 = height << 1; + int hTimes4 = height << 2; + int buffer_size = hTimes4 * 3; + m_buffer = new ushort[buffer_size >> 1]; + m_dst = 0; + InitFrame(); + InitBitReader(); + ushort p = ReadPair (0); + for (int i = 0; i < hTimes2+1; ++i) + m_buffer[i] = p; + int dst = hTimes4; + int prev_src = 0; + while (m_dst < m_pixels.Length) + { + bool same_line = false; + int src = -hTimes2; + if (GetNextBit() != 0) // @1@ + { + if (GetNextBit() == 0) // @4@ + src += 4; + else if (GetNextBit() == 0) // @5@ + src -= 4; + else + src <<= 1; + } + else if (GetNextBit() == 0) // @2@ + { + src = -4; + p = m_buffer[dst/2-1]; + if ((p & 0xFF) == (p >> 8)) + same_line = src != prev_src; + } + if (src != prev_src) // @6@ + { + prev_src = src; + if (!same_line) + src += dst; + else + src = dst - 2; + if (GetNextBit() != 0) // @3@ + { + int bitlength = 0; + do + { + ++bitlength; + } + while (GetNextBit() != 0); + int count = 1; + while (bitlength --> 0) + count = count << 1 | GetNextBit(); + MovePixels (m_buffer, src, dst, count); + dst += count << 1; + if (dst == buffer_size) + { + if (FlushBuffer()) + return; + dst = hTimes4; + } + } + else + { + MovePixels (m_buffer, src, dst, 1); + dst += 2; + if (dst == buffer_size) + { + if (FlushBuffer()) + return; + dst = hTimes4; + } + } + } + else + { + p = m_buffer[dst/2-1]; + do + { + byte prev = (byte)(p >> 8); + p = ReadPair (prev); + m_buffer[dst >> 1] = p; + dst += 2; + if (dst == buffer_size) + { + if (FlushBuffer()) + return; + dst = hTimes4; + } + } + while (GetNextBit() != 0); + prev_src = 0; + } + } + } + + bool FlushBuffer () + { + int height = m_info.iHeight; + int src_line = height << 1; + int dst = m_dst; + for (int i = 0; i < height; ++i) + { + int src = src_line; + for (int j = 0; j < 4; ++j) + { + ushort p = m_buffer[src]; + m_pixels[dst+j] = (byte)((p & 0xF0) | p >> 12); + src += height; + } + src_line++; + dst += m_output_stride; + } + m_dst += 4; + MovePixels (m_buffer, height << 3, 0, height << 1); + return m_dst >= m_output_stride; + } + BitmapPalette ReadPalette () { var colors = new Color[16];