mirror of
https://github.com/crskycode/GARbro.git
synced 2026-07-08 01:30:18 +08:00
bunch of stuff.
This commit is contained in:
@@ -23,10 +23,14 @@
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using GameRes.Utility;
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
|
||||
// [980626][Love Gun] ACE OF SPADES 2
|
||||
|
||||
namespace GameRes.Formats.HyperWorks
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
@@ -51,7 +55,8 @@ namespace GameRes.Formats.HyperWorks
|
||||
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
return ImageData.Create (info, format, palette, pixels);
|
||||
var reader = new I24Decoder (file, info);
|
||||
return reader.Unpack();
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
@@ -59,4 +64,439 @@ namespace GameRes.Formats.HyperWorks
|
||||
throw new System.NotImplementedException ("I24Format.Write not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
internal class I24Decoder
|
||||
{
|
||||
IBinaryStream m_input;
|
||||
ImageMetaData m_info;
|
||||
|
||||
public I24Decoder (IBinaryStream input, ImageMetaData info)
|
||||
{
|
||||
m_input = input;
|
||||
m_info = info;
|
||||
}
|
||||
|
||||
static readonly short[] shiftTable = new short[] {
|
||||
-1, 0, 0, 1, 1, 1, -1, 1, 2, 1, -2, 1, -2, 0, 0, 2, 1, 2, -1, 2, -3, 0
|
||||
};
|
||||
|
||||
bool cacheEmpty = true;
|
||||
int byteCount = 0;
|
||||
int bits = 0;
|
||||
int bitCount = 0;
|
||||
|
||||
class Node
|
||||
{
|
||||
public Node next;
|
||||
public int depth;
|
||||
public int token;
|
||||
}
|
||||
|
||||
struct DictRec
|
||||
{
|
||||
public Link link;
|
||||
public int bitSize;
|
||||
public int token;
|
||||
}
|
||||
|
||||
class Link
|
||||
{
|
||||
public Link[] children = new Link[2];
|
||||
public int token;
|
||||
}
|
||||
|
||||
DictRec[] dTable_1 = new DictRec[256];
|
||||
DictRec[] dTable_2 = new DictRec[256];
|
||||
DictRec[] dTable_3 = new DictRec[256];
|
||||
|
||||
Link[] tBuffer_1 = InitNodeList<Link> (684);
|
||||
Link[] tBuffer_2 = InitNodeList<Link> (22);
|
||||
Link[] tBuffer_3 = InitNodeList<Link> (502);
|
||||
|
||||
Node[] bTable_1 = InitNodeList<Node> (342);
|
||||
Node[] bTable_2 = InitNodeList<Node> (11);
|
||||
Node[] bTable_3 = InitNodeList<Node> (251);
|
||||
|
||||
static T[] InitNodeList<T>(int count) where T : new()
|
||||
{
|
||||
var list = new T[count];
|
||||
for (int i = 0; i < count; ++i)
|
||||
list[i] = new T();
|
||||
return list;
|
||||
}
|
||||
|
||||
public ImageData Unpack ()
|
||||
{
|
||||
m_input.Position = 0x18;
|
||||
int stride = m_info.iWidth * 4;
|
||||
var pixels = new byte[stride * m_info.iHeight];
|
||||
byte[][] line_buffer = new[] { new byte[stride], new byte[stride], new byte[stride] };
|
||||
int dst = 0;
|
||||
var shift_table = shiftTable.Clone() as short[];
|
||||
for (int y = 0; y < m_info.iHeight; ++y)
|
||||
{
|
||||
var line = line_buffer[2];
|
||||
line_buffer[2] = line_buffer[1];
|
||||
line_buffer[1] = line_buffer[0];
|
||||
line_buffer[0] = line;
|
||||
int x = 0;
|
||||
int p = 0;
|
||||
while (x < m_info.iWidth)
|
||||
{
|
||||
if (byteCount-- == 0)
|
||||
{
|
||||
if (cacheEmpty)
|
||||
{
|
||||
cacheEmpty = false;
|
||||
int val = ReadUInt8() << 8;
|
||||
val |= ReadUInt8();
|
||||
bits = val;
|
||||
bitCount = 8;
|
||||
}
|
||||
InitTree (bTable_1, 342);
|
||||
InitTree (bTable_2, 11);
|
||||
InitTree (bTable_3, 251);
|
||||
|
||||
RebuildTree(bTable_1, dTable_1, tBuffer_1, 342);
|
||||
RebuildTree(bTable_2, dTable_2, tBuffer_2, 11);
|
||||
RebuildTree(bTable_3, dTable_3, tBuffer_3, 251);
|
||||
byteCount = 0x3FFF;
|
||||
}
|
||||
int color_token = GetToken (dTable_1);
|
||||
int shift_token = GetToken (dTable_2);
|
||||
|
||||
int shift_idx = 2 * shift_token;
|
||||
short s1 = shift_table[shift_idx];
|
||||
short s2 = shift_table[shift_idx + 1];
|
||||
if (shift_token != 0)
|
||||
{
|
||||
while (shift_token --> 0)
|
||||
{
|
||||
shift_table[shift_idx] = shift_table[shift_idx - 2];
|
||||
shift_table[shift_idx+1] = shift_table[shift_idx - 1];
|
||||
shift_idx -= 2;
|
||||
}
|
||||
shift_table[0] = s1;
|
||||
shift_table[1] = s2;
|
||||
}
|
||||
int src = 4 * (x + s1);
|
||||
if (color_token >= 216)
|
||||
{
|
||||
int count = color_token - 214;
|
||||
x += count;
|
||||
while (count --> 0)
|
||||
{
|
||||
line[p++] = line_buffer[s2][src++];
|
||||
line[p++] = line_buffer[s2][src++];
|
||||
line[p++] = line_buffer[s2][src++];
|
||||
line[p++] = line_buffer[s2][src++];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sbyte r = shift_R[color_token];
|
||||
if (r == -3)
|
||||
r = (sbyte)(GetToken (dTable_3) + 3);
|
||||
line[p+2] = (byte)(line_buffer[s2][src+2] - r);
|
||||
|
||||
sbyte g = shift_G[color_token];
|
||||
if (g == -3)
|
||||
g = (sbyte)(GetToken(dTable_3) + 3);
|
||||
line[p+1] = (byte)(line_buffer[s2][src+1] - g);
|
||||
|
||||
sbyte b = shift_B[color_token];
|
||||
if (b == -3)
|
||||
b = (sbyte)(GetToken(dTable_3) + 3);
|
||||
line[p] = (byte)(line_buffer[s2][src] - b);
|
||||
line[p+3] = 0;
|
||||
p += 4;
|
||||
++x;
|
||||
}
|
||||
}
|
||||
Buffer.BlockCopy (line_buffer[0], 0, pixels, dst, stride);
|
||||
dst += stride;
|
||||
}
|
||||
return ImageData.Create (m_info, PixelFormats.Bgr32, null, pixels, stride);
|
||||
}
|
||||
|
||||
private void InitTree (Node[] tree, int count) // sub_408FB0
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
tree[i].next = null;
|
||||
tree[i].depth = 0;
|
||||
tree[i].token = i;
|
||||
}
|
||||
int length = GetBitLength();
|
||||
if (length <= 1)
|
||||
return;
|
||||
length -= 1;
|
||||
int fieldWidth = GetBits (3);
|
||||
int tIdx = 0;
|
||||
while (length > 0)
|
||||
{
|
||||
if (GetNextBit() != 0)
|
||||
{
|
||||
tree[tIdx++].depth = GetBits (fieldWidth);
|
||||
--length;
|
||||
}
|
||||
else
|
||||
{
|
||||
int step = GetBitLength();
|
||||
if (0 == step)
|
||||
tIdx++;
|
||||
else
|
||||
tIdx += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildTree (Node[] tree, DictRec[] dict, Link[] links, int count)
|
||||
{
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
dict[i].token = 0;
|
||||
dict[i].link = null;
|
||||
}
|
||||
int next_idx = 0; // var node = tree;
|
||||
count -= 1;
|
||||
while (0 == tree[next_idx].depth)
|
||||
{
|
||||
if (--count <= 0)
|
||||
break;
|
||||
++next_idx;
|
||||
}
|
||||
if (0 == count)
|
||||
return;
|
||||
|
||||
var node = tree[next_idx++];
|
||||
while (count --> 0)
|
||||
{
|
||||
int depth = tree[next_idx].depth;
|
||||
if (depth != 0)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
if (node.depth <= depth)
|
||||
{
|
||||
var prev = node;
|
||||
var ptr = node.next;
|
||||
while (ptr != null)
|
||||
{
|
||||
if (ptr.depth > depth)
|
||||
break;
|
||||
prev = ptr;
|
||||
ptr = ptr.next;
|
||||
}
|
||||
prev.next = tree[next_idx];
|
||||
tree[next_idx].next = ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
tree[next_idx].next = node;
|
||||
node = tree[next_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
++next_idx;
|
||||
}
|
||||
|
||||
int bit_size = 0;
|
||||
int t3_i = 0;
|
||||
int dict_idx = 0;
|
||||
while (node != null)
|
||||
{
|
||||
if (node.depth > bit_size)
|
||||
{
|
||||
dict_idx <<= node.depth - bit_size;
|
||||
bit_size = node.depth;
|
||||
}
|
||||
if (bit_size >= 8)
|
||||
{
|
||||
if (bit_size == 8)
|
||||
{
|
||||
dict[dict_idx].bitSize = 8;
|
||||
dict[dict_idx].token = node.token;
|
||||
dict[dict_idx].link = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
int d1 = bit_size - 8;
|
||||
int d2 = dict_idx >> d1;
|
||||
int d3 = dict_idx << (32 - (bit_size - 8));
|
||||
dict[d2].bitSize = 0;
|
||||
var ptr_t2 = d2; // &dict[d2];
|
||||
var link = dict[ptr_t2].link;
|
||||
if (null == link)
|
||||
{
|
||||
var t3_ptr = links[t3_i];
|
||||
t3_ptr.children[0] = null;
|
||||
t3_ptr.children[1] = null;
|
||||
t3_ptr.token = 0;
|
||||
link = t3_ptr;
|
||||
dict[ptr_t2].link = t3_ptr;
|
||||
t3_i++;
|
||||
}
|
||||
while (d1 --> 0)
|
||||
{
|
||||
int v26 = (d3 >> 31) & 1;
|
||||
d3 <<= 1;
|
||||
if (null == link.children[v26])
|
||||
{
|
||||
var t3_ptr = links[t3_i];
|
||||
t3_ptr.children[0] = null;
|
||||
t3_ptr.children[1] = null;
|
||||
t3_ptr.token = 0;
|
||||
link.children[v26] = t3_ptr;
|
||||
t3_i++;
|
||||
}
|
||||
link = link.children[v26];
|
||||
}
|
||||
link.token = node.token;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int d1 = dict_idx << (8 - bit_size);
|
||||
int d2 = 1 << (8 - bit_size);
|
||||
while (d2 --> 0)
|
||||
{
|
||||
dict[d1].bitSize = bit_size;
|
||||
dict[d1].token = node.token;
|
||||
d1++;
|
||||
}
|
||||
}
|
||||
++dict_idx;
|
||||
node = node.next;
|
||||
}
|
||||
}
|
||||
|
||||
int GetToken (DictRec[] table)
|
||||
{
|
||||
var table_ptr = table[(bits >> 8) & 0xFF];
|
||||
int count = table_ptr.bitSize;
|
||||
if (count != 0)
|
||||
{
|
||||
if (count >= bitCount)
|
||||
{
|
||||
bits <<= bitCount;
|
||||
count -= bitCount;
|
||||
bits |= ReadUInt8();
|
||||
bitCount = 8;
|
||||
}
|
||||
bits <<= count;
|
||||
bitCount -= count;
|
||||
return table_ptr.token;
|
||||
}
|
||||
else
|
||||
{
|
||||
bits = ReadUInt8() | bits << bitCount;
|
||||
bits <<= 8 - bitCount;
|
||||
Link link = table_ptr.link;
|
||||
do
|
||||
{
|
||||
int path = GetNextBit() & 1;
|
||||
link = link.children[path];
|
||||
if (null == link)
|
||||
throw new InvalidFormatException ("Invalid tree path");
|
||||
}
|
||||
while (link.children[0] != null);
|
||||
return link.token;
|
||||
}
|
||||
}
|
||||
|
||||
private byte ReadUInt8()
|
||||
{
|
||||
return (byte)m_input.ReadByte();
|
||||
}
|
||||
|
||||
private int GetNextBit ()
|
||||
{
|
||||
bits <<= 1;
|
||||
if (0 == --bitCount)
|
||||
{
|
||||
bits |= ReadUInt8();
|
||||
bitCount = 8;
|
||||
}
|
||||
return (bits >> 16) & 1;
|
||||
}
|
||||
|
||||
private int GetBitLength ()
|
||||
{
|
||||
if (GetNextBit() != 0)
|
||||
return 0;
|
||||
int i = 0;
|
||||
do
|
||||
{
|
||||
++i;
|
||||
}
|
||||
while (0 == GetNextBit());
|
||||
return (1 << i) | GetBits (i);
|
||||
}
|
||||
|
||||
private int GetBits (int count)
|
||||
{
|
||||
int n = count;
|
||||
if (count >= bitCount)
|
||||
{
|
||||
bits <<= bitCount;
|
||||
n = count - bitCount;
|
||||
bits |= ReadUInt8();
|
||||
bitCount = 8;
|
||||
}
|
||||
if (n >= 8)
|
||||
{
|
||||
bits <<= 8;
|
||||
bits |= ReadUInt8();
|
||||
n -= 8;
|
||||
}
|
||||
bits <<= n;
|
||||
bitCount -= n;
|
||||
return (bits >> 16) & bitMask[count];
|
||||
}
|
||||
|
||||
static readonly int[] bitMask = new[] {
|
||||
0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
|
||||
0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,
|
||||
0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,
|
||||
0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF
|
||||
};
|
||||
|
||||
static readonly sbyte[] shift_R = new sbyte[] {
|
||||
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
|
||||
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
|
||||
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
};
|
||||
static readonly sbyte[] shift_G = new sbyte[] {
|
||||
-3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, -3, -3, -3, -3, -3, -3, -2, -2, -2,
|
||||
-2, -2, -2, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2,
|
||||
2, 2, 2, 2, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1,
|
||||
-1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, -3, -3, -3, -3,
|
||||
-3, -3, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2,
|
||||
-2, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
2, 2, -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1,
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
|
||||
};
|
||||
static readonly sbyte[] shift_B = new sbyte[] {
|
||||
-3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2,
|
||||
-3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0,
|
||||
1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2,
|
||||
-1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2,
|
||||
-3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0,
|
||||
1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2,
|
||||
-1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2,
|
||||
-3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0,
|
||||
1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2,
|
||||
-1, 0, 1, 2, -3, -2, -1, 0, 1, 2, -3, -2, -1, 0, 1, 2,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user