(WBM): image compression variations.

This commit is contained in:
morkt 2016-08-07 20:36:02 +04:00
parent 1cf89e33b6
commit da15b1f31f

View File

@ -2,7 +2,7 @@
//! \date Thu Jul 09 20:59:09 2015
//! \brief Wild Bug's image format.
//
// Copyright (C) 2015 by morkt
// Copyright (C) 2015-2016 by morkt
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
@ -136,6 +136,10 @@ namespace GameRes.Formats.WildBug
format = PixelFormats.Bgr555;
pixel_size = 2;
break;
case 8:
format = PixelFormats.Indexed8;
pixel_size = 1;
break;
default:
throw new NotSupportedException ("Not supported WBM bitdepth");
}
@ -144,6 +148,18 @@ namespace GameRes.Formats.WildBug
var pixels = reader.Unpack (stride, pixel_size, section.DataFormat);
if (null == pixels)
throw new InvalidFormatException();
if (8 == meta.BPP)
{
section = WpxSection.Find (meta.Header, 0x12, meta.EntryCount, meta.EntrySize);
if (null == section)
return ImageData.Create (info, PixelFormats.Gray8, null, pixels, stride);
reader = new WbmReader (stream, section);
var palette_data = reader.Unpack (48, 3, section.DataFormat);
var palette = CreatePalette (palette_data);
return ImageData.Create (info, PixelFormats.Indexed8, palette, pixels, stride);
}
if (meta.BPP < 24)
return ImageData.Create (info, format, null, pixels, stride);
section = WpxSection.Find (meta.Header, 0x13, meta.EntryCount, meta.EntrySize);
@ -183,6 +199,18 @@ namespace GameRes.Formats.WildBug
{
throw new System.NotImplementedException ("WbmFormat.Write not implemented");
}
static BitmapPalette CreatePalette (byte[] palette_data)
{
int colors = Math.Min (palette_data.Length/3, 0x100);
var palette = new Color[0x100];
for (int i = 0; i < colors; ++i)
{
int c = i * 3;
palette[i] = Color.FromRgb (palette_data[c], palette_data[c+1], palette_data[c+2]);
}
return new BitmapPalette (palette);
}
}
internal class WbmReader : WpxDecoder
@ -237,14 +265,16 @@ namespace GameRes.Formats.WildBug
}
}
int m_version;
int m_condition;
public byte[] Unpack (int stride, int pixel_size, int flags) // sub_40919C
{
int[] offset_table = new int[8];
GenerateOffsetTableV2 (offset_table, stride, pixel_size);
for (m_condition = 1; m_condition >= 0; --m_condition)
for (m_version = 2; m_version >= 0; --m_version)
{
m_condition = m_version > 0 ? 1 : 0;
try
{
ResetInput();
@ -281,16 +311,16 @@ namespace GameRes.Formats.WildBug
}
catch
{
if (0 == m_condition)
if (0 == m_version)
throw;
}
GenerateOffsetTableV1 (offset_table, stride, pixel_size);
if (1 == m_version)
GenerateOffsetTableV1 (offset_table, stride, pixel_size);
}
return null;
}
byte[] UnpackVD (byte[] a4, int[] offset_table, int pixel_size) // 0x0F format
// int sub_460470(void *dst, const void *src, unsigned __int8 *ref_table, unsigned int packed_size, int *offset_table, int unpacked_size, unsigned int pixel_size)
{
byte[] v47 = BuildTable(); //sub_46C26C();
int min_count = 1 == pixel_size ? 2 : 1;
@ -448,11 +478,60 @@ namespace GameRes.Formats.WildBug
byte[] UnpackV9 (int[] offset_table, int pixel_size) // 0x09 format
{
throw new NotImplementedException();
int min_count = 1 == pixel_size ? 2 : 1;
m_available = FillBuffer();
if (0 == m_available)
return null;
int step = (pixel_size + 3) & -4;
if (m_available < step)
return null;
Buffer.BlockCopy (m_buffer, 0, m_output, 0, pixel_size);
int dst = pixel_size;
int remaining = m_output.Length - pixel_size;
m_current = pixel_size + (-pixel_size & 3);
m_bits = m_buffer[m_current++];
m_bit_count = 8;
while (remaining > 0)
{
while (0 == (GetNextBit() ^ m_condition))
{
m_output[dst++] = ReadNext();
--remaining;
if (0 == remaining)
return m_output;
}
int count, src_offset;
if (GetNextBit() != 0)
{
src_offset = dst - 1 - ReadNext();
count = 2;
}
else
{
count = min_count;
int v35 = GetNextBit();
v35 += v35 + GetNextBit();
v35 += v35 + GetNextBit();
src_offset = dst - offset_table[v35];
}
if (GetNextBit() == 0)
{
count += ReadCount();
}
if (remaining < count)
return null;
Binary.CopyOverlapped (m_output, src_offset, dst, count);
dst += count;
remaining -= count;
}
return m_output;
}
byte[] UnpackV5 (byte[] a4, int[] offset_table, int pixel_size) // 0x07 format
// int sub_409AF4 (void *a1, FILE *stream, void *ptr, void *a4, unsigned int m_packed_size, int *offset_table, int unpacked_size, unsigned int pixel_size)
{
byte[] v46 = BuildTable();
int min_count = 1 == pixel_size ? 2 : 1;
@ -506,21 +585,50 @@ namespace GameRes.Formats.WildBug
if (0 == remaining)
return m_output;
}
int src_offset;
int count;
if (GetNextBit() != 0)
int count, src_offset;
if (m_version > 1)
{
count = min_count;
int v32 = GetNextBit() << 2;
v32 |= GetNextBit() << 1;
v32 |= GetNextBit();
src_offset = dst - offset_table[v32];
if (GetNextBit() != 0)
{
int v35;
if (GetNextBit() != 0)
{
v35 = ReadNext();
count = 2;
}
else
{
v35 = ReadNext();
v35 |= ReadNext() << 8;
count = 3;
}
src_offset = dst - 1 - v35;
}
else
{
count = min_count;
int v35 = GetNextBit();
v35 += v35 + GetNextBit();
v35 += v35 + GetNextBit();
src_offset = dst - offset_table[v35];
}
}
else
{
byte v35 = ReadNext();
count = 2;
src_offset = dst - 1 - v35;
if (GetNextBit() != 0)
{
count = min_count;
int v32 = GetNextBit() << 2;
v32 |= GetNextBit() << 1;
v32 |= GetNextBit();
src_offset = dst - offset_table[v32];
}
else
{
byte v35 = ReadNext();
count = 2;
src_offset = dst - 1 - v35;
}
}
if (0 == GetNextBit())
{
@ -536,7 +644,6 @@ namespace GameRes.Formats.WildBug
}
byte[] UnpackV4 (byte[] a4, int[] offset_table, int pixel_size) // 0x06 format
// signed int __cdecl sub_40B044(void *a1, FILE *stream, void *ptr, void *a4, unsigned int packed_size, int *offset_table, int unpacked_size, unsigned int pixel_size)
{
byte[] v48 = BuildTable();
int min_count = 1 == pixel_size ? 2 : 1;
@ -615,7 +722,6 @@ namespace GameRes.Formats.WildBug
}
byte[] UnpackV3 (byte[] a4, int[] offset_table, int pixel_size) // 0x03 format
// int sub_409F70(void *a1, FILE *stream, void *ptr, void *a4, unsigned int packed_size, int *offset_table, int unpacked_size, unsigned int pixel_size)
{
int min_count = 1 == pixel_size ? 2 : 1;
@ -660,19 +766,48 @@ namespace GameRes.Formats.WildBug
return m_output;
}
int count, src_offset;
if (GetNextBit() != 0)
if (m_version > 1)
{
count = min_count;
int v28 = GetNextBit() << 1;
v28 |= GetNextBit();
v28 <<= 1;
v28 |= GetNextBit();
src_offset = dst - offset_table[v28];
if (GetNextBit() != 0)
{
if (GetNextBit() != 0)
{
count = 2;
src_offset = ReadNext();
}
else
{
count = 3;
src_offset = ReadNext();
src_offset |= ReadNext() << 8;
}
src_offset = dst - 1 - src_offset;
}
else
{
count = min_count;
int v28 = GetNextBit();
v28 += v28 + GetNextBit();
v28 += v28 + GetNextBit();
src_offset = dst - offset_table[v28];
}
}
else
{
count = 2;
src_offset = dst - 1 - ReadNext();
if (GetNextBit() != 0)
{
count = min_count;
int v28 = GetNextBit() << 1;
v28 |= GetNextBit();
v28 <<= 1;
v28 |= GetNextBit();
src_offset = dst - offset_table[v28];
}
else
{
count = 2;
src_offset = dst - 1 - ReadNext();
}
}
if (GetNextBit() == 0)
{
@ -688,9 +823,7 @@ namespace GameRes.Formats.WildBug
}
byte[] UnpackV2 (byte[] a4, int[] offset_table, int pixel_size) // 0x02 format
// int sub_40B458(void *a1, FILE *stream, unsigned __int8 *ptr, void *a4, unsigned int packed_size, int *offset_table, int unpacked_size, unsigned int a8)
{
byte[] v48 = BuildTable();
int min_count = 1 == pixel_size ? 2 : 1;
m_available = FillBuffer();
if (0 == m_available)
@ -756,7 +889,6 @@ namespace GameRes.Formats.WildBug
}
byte[] UnpackV1 (int[] offset_table, int pixel_size) // 0x01 format
//int sub_40A3C4(void *a1, FILE *stream, const void *ptr, unsigned int packed_size, int *offset_table, int unpacked_size, unsigned int pixel_size)
{
int min_count = 1 == pixel_size ? 2 : 1;
m_available = FillBuffer();
@ -784,18 +916,47 @@ namespace GameRes.Formats.WildBug
return m_output;
}
int count, src_offset;
if (GetNextBit() != 0)
if (m_version > 1)
{
count = min_count;
int v14 = GetNextBit() << 2;
v14 |= GetNextBit() << 1;
v14 |= GetNextBit();
src_offset = dst - offset_table[v14];
if (GetNextBit() != 0)
{
if (GetNextBit() != 0)
{
src_offset = ReadNext();
count = 2;
}
else
{
src_offset = ReadNext();
src_offset |= ReadNext() << 8;
count = 3;
}
src_offset = dst - 1 - src_offset;
}
else
{
count = min_count;
int v20 = GetNextBit();
v20 += v20 + GetNextBit();
v20 += v20 + GetNextBit();
src_offset = dst - offset_table[v20];
}
}
else
{
count = 2;
src_offset = dst - 1 - ReadNext();
if (GetNextBit() != 0)
{
count = min_count;
int v14 = GetNextBit() << 2;
v14 |= GetNextBit() << 1;
v14 |= GetNextBit();
src_offset = dst - offset_table[v14];
}
else
{
count = 2;
src_offset = dst - 1 - ReadNext();
}
}
if (GetNextBit() == 0)
{
@ -811,7 +972,6 @@ namespace GameRes.Formats.WildBug
}
byte[] UnpackV0 (int[] offset_table, int pixel_size) // 0x00 format
// int sub_40B83C(void *a1, FILE *stream, const void *ptr, unsigned int packed_size, int *a5, int unpacked_size, unsigned int pixel_size)
{
int min_count = 1 == pixel_size ? 2 : 1;
m_available = FillBuffer();