mirror of
https://github.com/crskycode/GARbro.git
synced 2024-12-24 03:44:13 +08:00
huffman tree implementation moved to separate class.
This commit is contained in:
parent
7078e586be
commit
36ebffb010
@ -248,7 +248,7 @@ namespace GameRes.Formats.BGI
|
|||||||
uint[] leaf_nodes_weight;
|
uint[] leaf_nodes_weight;
|
||||||
using (var enc = new MemoryStream (ReadEncoded()))
|
using (var enc = new MemoryStream (ReadEncoded()))
|
||||||
leaf_nodes_weight = ReadWeightTable (enc, 0x100);
|
leaf_nodes_weight = ReadWeightTable (enc, 0x100);
|
||||||
var tree = CreateHuffmanTree (leaf_nodes_weight);
|
var tree = new HuffmanTree (leaf_nodes_weight);
|
||||||
byte[] packed = new byte[m_info.IntermediateLength];
|
byte[] packed = new byte[m_info.IntermediateLength];
|
||||||
|
|
||||||
HuffmanDecompress (tree, packed);
|
HuffmanDecompress (tree, packed);
|
||||||
@ -257,11 +257,11 @@ namespace GameRes.Formats.BGI
|
|||||||
ReverseAverageSampling();
|
ReverseAverageSampling();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HuffmanDecompress (HuffmanNode[] tree, byte[] output)
|
void HuffmanDecompress (HuffmanTree tree, byte[] output)
|
||||||
{
|
{
|
||||||
for (int dst = 0; dst < output.Length; dst++)
|
for (int dst = 0; dst < output.Length; dst++)
|
||||||
{
|
{
|
||||||
output[dst] = (byte)DecodeToken (this, tree);
|
output[dst] = (byte)tree.DecodeToken (this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +330,55 @@ namespace GameRes.Formats.BGI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class HuffmanNode
|
void UnpackV2 ()
|
||||||
|
{
|
||||||
|
if (m_info.EncLength < 0x80)
|
||||||
|
throw new InvalidFormatException();
|
||||||
|
var decoder = new ParallelCbgDecoder (m_info, ReadEncoded());
|
||||||
|
var base_offset = Input.Position;
|
||||||
|
decoder.Tree1 = new HuffmanTree (ReadWeightTable (Input, 0x10), true);
|
||||||
|
decoder.Tree2 = new HuffmanTree (ReadWeightTable (Input, 0xB0), true);
|
||||||
|
|
||||||
|
int y_blocks = decoder.Height / 8;
|
||||||
|
var offsets = new int[y_blocks+1];
|
||||||
|
int input_base = (int)(Input.Position + offsets.Length*4 - base_offset);
|
||||||
|
using (var reader = new ArcView.Reader (Input))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < offsets.Length; ++i)
|
||||||
|
offsets[i] = reader.ReadInt32() - input_base;
|
||||||
|
decoder.Input = reader.ReadBytes ((int)(Input.Length - Input.Position));
|
||||||
|
}
|
||||||
|
int pad_skip = ((decoder.Width >> 3) + 7) >> 3;
|
||||||
|
var tasks = new List<Task> (y_blocks+1);
|
||||||
|
decoder.Output = new byte[decoder.Width * decoder.Height * 4];
|
||||||
|
int dst = 0;
|
||||||
|
for (int i = 0; i < y_blocks; ++i)
|
||||||
|
{
|
||||||
|
int block_offset = offsets[i] + pad_skip;
|
||||||
|
int next_offset = i+1 == y_blocks ? decoder.Input.Length : offsets[i+1];
|
||||||
|
int closure_dst = dst;
|
||||||
|
var task = Task.Run (() => decoder.UnpackBlock (block_offset, next_offset-block_offset, closure_dst));
|
||||||
|
tasks.Add (task);
|
||||||
|
dst += decoder.Width * 32;
|
||||||
|
}
|
||||||
|
if (32 == m_info.BPP)
|
||||||
|
{
|
||||||
|
var task = Task.Run (() => decoder.UnpackAlpha (offsets[y_blocks]));
|
||||||
|
tasks.Add (task);
|
||||||
|
}
|
||||||
|
var complete = Task.WhenAll (tasks);
|
||||||
|
complete.Wait();
|
||||||
|
Format = decoder.HasAlpha ? PixelFormats.Bgra32 : PixelFormats.Bgr32;
|
||||||
|
Stride = decoder.Width * 4;
|
||||||
|
m_output = decoder.Output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class HuffmanTree
|
||||||
|
{
|
||||||
|
HuffmanNode[] m_nodes;
|
||||||
|
|
||||||
|
class HuffmanNode
|
||||||
{
|
{
|
||||||
public bool Valid;
|
public bool Valid;
|
||||||
public bool IsParent;
|
public bool IsParent;
|
||||||
@ -339,7 +387,7 @@ namespace GameRes.Formats.BGI
|
|||||||
public int RightChildIndex;
|
public int RightChildIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HuffmanNode[] CreateHuffmanTree (uint[] leaf_nodes_weight, bool v2 = false)
|
public HuffmanTree (uint[] leaf_nodes_weight, bool v2 = false)
|
||||||
{
|
{
|
||||||
var node_list = new List<HuffmanNode> (leaf_nodes_weight.Length * 2);
|
var node_list = new List<HuffmanNode> (leaf_nodes_weight.Length * 2);
|
||||||
uint root_node_weight = 0;
|
uint root_node_weight = 0;
|
||||||
@ -401,68 +449,25 @@ namespace GameRes.Formats.BGI
|
|||||||
if (weight >= root_node_weight)
|
if (weight >= root_node_weight)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return node_list.ToArray();
|
m_nodes = node_list.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int DecodeToken (MsbBitStream input, HuffmanNode[] tree)
|
public int DecodeToken (IBitStream input)
|
||||||
{
|
{
|
||||||
int node_index = tree.Length-1;
|
int node_index = m_nodes.Length-1;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int bit = input.GetNextBit();
|
int bit = input.GetNextBit();
|
||||||
if (-1 == bit)
|
if (-1 == bit)
|
||||||
throw new EndOfStreamException();
|
throw new EndOfStreamException();
|
||||||
if (0 == bit)
|
if (0 == bit)
|
||||||
node_index = tree[node_index].LeftChildIndex;
|
node_index = m_nodes[node_index].LeftChildIndex;
|
||||||
else
|
else
|
||||||
node_index = tree[node_index].RightChildIndex;
|
node_index = m_nodes[node_index].RightChildIndex;
|
||||||
}
|
}
|
||||||
while (tree[node_index].IsParent);
|
while (m_nodes[node_index].IsParent);
|
||||||
return node_index;
|
return node_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnpackV2 ()
|
|
||||||
{
|
|
||||||
if (m_info.EncLength < 0x80)
|
|
||||||
throw new InvalidFormatException();
|
|
||||||
var decoder = new ParallelCbgDecoder (m_info, ReadEncoded());
|
|
||||||
var base_offset = Input.Position;
|
|
||||||
decoder.Tree1 = CreateHuffmanTree (ReadWeightTable (Input, 0x10), true);
|
|
||||||
decoder.Tree2 = CreateHuffmanTree (ReadWeightTable (Input, 0xB0), true);
|
|
||||||
|
|
||||||
int y_blocks = decoder.Height / 8;
|
|
||||||
var offsets = new int[y_blocks+1];
|
|
||||||
int input_base = (int)(Input.Position + offsets.Length*4 - base_offset);
|
|
||||||
using (var reader = new ArcView.Reader (Input))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < offsets.Length; ++i)
|
|
||||||
offsets[i] = reader.ReadInt32() - input_base;
|
|
||||||
decoder.Input = reader.ReadBytes ((int)(Input.Length - Input.Position));
|
|
||||||
}
|
|
||||||
int pad_skip = ((decoder.Width >> 3) + 7) >> 3;
|
|
||||||
var tasks = new List<Task> (y_blocks+1);
|
|
||||||
decoder.Output = new byte[decoder.Width * decoder.Height * 4];
|
|
||||||
int dst = 0;
|
|
||||||
for (int i = 0; i < y_blocks; ++i)
|
|
||||||
{
|
|
||||||
int block_offset = offsets[i] + pad_skip;
|
|
||||||
int next_offset = i+1 == y_blocks ? decoder.Input.Length : offsets[i+1];
|
|
||||||
int closure_dst = dst;
|
|
||||||
var task = Task.Run (() => decoder.UnpackBlock (block_offset, next_offset-block_offset, closure_dst));
|
|
||||||
tasks.Add (task);
|
|
||||||
dst += decoder.Width * 32;
|
|
||||||
}
|
|
||||||
if (32 == m_info.BPP)
|
|
||||||
{
|
|
||||||
var task = Task.Run (() => decoder.UnpackAlpha (offsets[y_blocks]));
|
|
||||||
tasks.Add (task);
|
|
||||||
}
|
|
||||||
var complete = Task.WhenAll (tasks);
|
|
||||||
complete.Wait();
|
|
||||||
Format = decoder.HasAlpha ? PixelFormats.Bgra32 : PixelFormats.Bgr32;
|
|
||||||
Stride = decoder.Width * 4;
|
|
||||||
m_output = decoder.Output;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class ParallelCbgDecoder
|
internal class ParallelCbgDecoder
|
||||||
@ -472,8 +477,8 @@ namespace GameRes.Formats.BGI
|
|||||||
public int BPP;
|
public int BPP;
|
||||||
public int Width;
|
public int Width;
|
||||||
public int Height;
|
public int Height;
|
||||||
public CbgReader.HuffmanNode[] Tree1;
|
public HuffmanTree Tree1;
|
||||||
public CbgReader.HuffmanNode[] Tree2;
|
public HuffmanTree Tree2;
|
||||||
public bool HasAlpha = false;
|
public bool HasAlpha = false;
|
||||||
float[,] DCT = new float[2, 64];
|
float[,] DCT = new float[2, 64];
|
||||||
|
|
||||||
@ -512,7 +517,7 @@ namespace GameRes.Formats.BGI
|
|||||||
int acc = 0;
|
int acc = 0;
|
||||||
for (int i = 0; i < block_size && input.Position < input.Length; i += 64)
|
for (int i = 0; i < block_size && input.Position < input.Length; i += 64)
|
||||||
{
|
{
|
||||||
int count = CbgReader.DecodeToken (reader, Tree1);
|
int count = Tree1.DecodeToken (reader);
|
||||||
if (count != 0)
|
if (count != 0)
|
||||||
{
|
{
|
||||||
int v = reader.GetBits (count);
|
int v = reader.GetBits (count);
|
||||||
@ -531,7 +536,7 @@ namespace GameRes.Formats.BGI
|
|||||||
int index = 1;
|
int index = 1;
|
||||||
while (index < 64 && input.Position < input.Length)
|
while (index < 64 && input.Position < input.Length)
|
||||||
{
|
{
|
||||||
int code = CbgReader.DecodeToken (reader, Tree2);
|
int code = Tree2.DecodeToken (reader);
|
||||||
if (0 == code)
|
if (0 == code)
|
||||||
break;
|
break;
|
||||||
if (0xF == code)
|
if (0xF == code)
|
||||||
@ -654,7 +659,7 @@ namespace GameRes.Formats.BGI
|
|||||||
int count = ((v >> 9) & 0x7F) + 3;
|
int count = ((v >> 9) & 0x7F) + 3;
|
||||||
|
|
||||||
int src = dst + (x + y * Width) * 4;
|
int src = dst + (x + y * Width) * 4;
|
||||||
if (src < 0 || src >= Output.Length)
|
if (src < 0 || src >= dst)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user