1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-09-27 05:35:57 -04:00

Finished data load logic for DCC files.

This commit is contained in:
Tim Sarbin 2018-12-06 23:11:36 -05:00
parent 20bacbbb14
commit 2f1f15c7b5
2 changed files with 89 additions and 77 deletions

View File

@ -47,13 +47,21 @@ namespace OpenDiablo2.Common.Models
private int MakeSigned(int value, int bits) private int MakeSigned(int value, int bits)
{ {
var msbSet = ((value & (1 << (bits - 1))) != 0); if (bits == 1)
if (msbSet) return -value;
if ((value & (1 << (bits - 1))) == 0)
return value;
var result = UInt32.MaxValue;
for (byte i = 0; i < bits; i++)
{ {
value = ~value + 1; if (((value >> i) & 1) == 0)
result -= (UInt32)(1 << i);
} }
return value; var newResult = (int)result;
return newResult;
} }
} }

View File

@ -8,7 +8,7 @@ namespace OpenDiablo2.Common.Models
{ {
public sealed class MPQDCC public sealed class MPQDCC
{ {
public struct PixelBufferEntry public class PixelBufferEntry
{ {
public byte[] Value; public byte[] Value;
public int Frame; public int Frame;
@ -62,23 +62,25 @@ namespace OpenDiablo2.Common.Models
public void MakeCells(MPQDCCDirection direction) public void MakeCells(MPQDCCDirection direction)
{ {
var w = 4 - ((Box.Left - direction.Box.Left) % 4); // Width of the first column (in pixels) var w = 4 - ((Box.Left - direction.Box.Left) % 4); // Width of the first column (in pixels)
if ((Box.Width - w) <= 1) if ((Width - w) <= 1)
HorizontalCellCount = 1; HorizontalCellCount = 1;
else else
{ {
HorizontalCellCount = 2 + ((Box.Width - w - 1) / 4); var tmp = Width - w - 1;
if (((Box.Width - w - 1) % 4) == 0) HorizontalCellCount = 2 + (tmp / 4);
if ((tmp % 4) == 0)
HorizontalCellCount--; HorizontalCellCount--;
} }
var h = 4 - ((Box.Top - direction.Box.Top) % 4); // Height of the first column (in pixels) var h = 4 - ((Box.Top - direction.Box.Top) % 4); // Height of the first column (in pixels)
if ((Box.Height - h) <= 1) if ((Height - h) <= 1)
VerticalCellCount = 1; VerticalCellCount = 1;
else else
{ {
VerticalCellCount = 2 + ((Box.Height - h - 1) / 4); var tmp = Height - h - 1;
if (((Box.Height - h - 1) % 4) == 0) VerticalCellCount = 2 + (tmp / 4);
if ((tmp % 4) == 0)
VerticalCellCount--; VerticalCellCount--;
} }
@ -87,24 +89,24 @@ namespace OpenDiablo2.Common.Models
// Calculate the cell widths and heights // Calculate the cell widths and heights
var cellWidths = new int[HorizontalCellCount]; var cellWidths = new int[HorizontalCellCount];
if (HorizontalCellCount == 1) if (HorizontalCellCount == 1)
cellWidths[0] = Box.Width; cellWidths[0] = Width;
else else
{ {
cellWidths[0] = w; cellWidths[0] = w;
for (var i = 1; i < (HorizontalCellCount - 1); i++) for (var i = 1; i < (HorizontalCellCount - 1); i++)
cellWidths[i] = 4; cellWidths[i] = 4;
cellWidths[HorizontalCellCount - 1] = Box.Width - w - (4 * (HorizontalCellCount - 2)); cellWidths[HorizontalCellCount - 1] = Width - w - (4 * (HorizontalCellCount - 2));
} }
var cellHeights = new int[VerticalCellCount]; var cellHeights = new int[VerticalCellCount];
if (VerticalCellCount == 1) if (VerticalCellCount == 1)
cellHeights[0] = Box.Height; cellHeights[0] = Height;
else else
{ {
cellHeights[0] = h; cellHeights[0] = h;
for (var i = 1; i < (VerticalCellCount - 1); i++) for (var i = 1; i < (VerticalCellCount - 1); i++)
cellHeights[i] = 4; cellHeights[i] = 4;
cellHeights[VerticalCellCount - 1] = Box.Height - h - (4 * (VerticalCellCount - 2)); cellHeights[VerticalCellCount - 1] = Height - h - (4 * (VerticalCellCount - 2));
} }
Cells = new Cell[HorizontalCellCount * VerticalCellCount]; Cells = new Cell[HorizontalCellCount * VerticalCellCount];
@ -129,6 +131,7 @@ namespace OpenDiablo2.Common.Models
} }
public sealed class MPQDCCDirection public sealed class MPQDCCDirection
{ {
const int DCC_MAX_PB_ENTRY = 85000; // But why is this the magic number?
public int OutSizeCoded { get; private set; } public int OutSizeCoded { get; private set; }
public int CompressionFlags { get; private set; } public int CompressionFlags { get; private set; }
public int Variable0Bits { get; private set; } public int Variable0Bits { get; private set; }
@ -148,7 +151,7 @@ namespace OpenDiablo2.Common.Models
public Cell[] Cells { get; private set; } public Cell[] Cells { get; private set; }
public int HorizontalCellCount { get; private set; } public int HorizontalCellCount { get; private set; }
public int VerticalCellCount { get; private set; } public int VerticalCellCount { get; private set; }
public List<PixelBufferEntry> PixelBuffer { get; private set; } public PixelBufferEntry[] PixelBuffer { get; private set; }
private static readonly byte[] crazyBitTable = { 0, 1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 26, 28, 30, 32 }; private static readonly byte[] crazyBitTable = { 0, 1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 26, 28, 30, 32 };
public MPQDCCDirection(BitMuncher bm, MPQDCC file) public MPQDCCDirection(BitMuncher bm, MPQDCC file)
@ -165,9 +168,6 @@ namespace OpenDiablo2.Common.Models
Frames = new MPQDCCDirectionFrame[file.NumberOfFrames]; Frames = new MPQDCCDirectionFrame[file.NumberOfFrames];
if (Variable0Bits != 0)
throw new ApplicationException("Variable0Bits is not 0. This is not ok.");
// Load the frame headers // Load the frame headers
for (var frameIdx = 0; frameIdx < file.NumberOfFrames; frameIdx++) for (var frameIdx = 0; frameIdx < file.NumberOfFrames; frameIdx++)
Frames[frameIdx] = new MPQDCCDirectionFrame(bm, this); Frames[frameIdx] = new MPQDCCDirectionFrame(bm, this);
@ -253,30 +253,32 @@ namespace OpenDiablo2.Common.Models
private void FillPixelBuffer(BitMuncher pcd, BitMuncher ec, BitMuncher pm, BitMuncher et, BitMuncher rp) private void FillPixelBuffer(BitMuncher pcd, BitMuncher ec, BitMuncher pm, BitMuncher et, BitMuncher rp)
{ {
UInt32 lastPixel = 0; UInt32 lastPixel = 0;
var cellBuffer = new int[HorizontalCellCount * VerticalCellCount]; // Store the offset to the cell buffer
for (var i = 0; i < cellBuffer.Length; i++) PixelBuffer = new PixelBufferEntry[DCC_MAX_PB_ENTRY];
cellBuffer[i] = -1; for (var i = 0; i < DCC_MAX_PB_ENTRY; i++)
PixelBuffer[i] = new PixelBufferEntry { Frame = -1, FrameCellIndex = -1, Value = new byte[4] };
PixelBuffer = new List<PixelBufferEntry>(); var cellBuffer = new PixelBufferEntry[Cells.Length];
var frameIndex = -1; var frameIndex = -1;
var pbIndex = -1;
UInt32 pixelMask = 0x00; UInt32 pixelMask = 0x00;
foreach (var frame in Frames) foreach (var frame in Frames)
{ {
frameIndex++; frameIndex++;
var originCellX = (frame.Box.Left - Box.Left) / 4; var originCellX = (frame.Box.Left - Box.Left) / 4;
var originCellY = (frame.Box.Top - Box.Top) / 4; var originCellY = (frame.Box.Top - Box.Top) / 4;
var frameCellIndex = 0;
for (var cellY = 0; cellY < frame.VerticalCellCount; cellY++) for (var cellY = 0; cellY < frame.VerticalCellCount; cellY++)
{ {
var currentCellY = cellY + originCellY; var currentCellY = cellY + originCellY;
for (var cellX = 0; cellX < frame.HorizontalCellCount; cellX++) for (var cellX = 0; cellX < frame.HorizontalCellCount; cellX++, frameCellIndex++)
{ {
var currentCell = (originCellX + cellX) + (currentCellY * HorizontalCellCount); var currentCell = (originCellX + cellX) + (currentCellY * frame.HorizontalCellCount);
var nextCell = false; var nextCell = false;
if (cellBuffer[currentCell] != -1) var tmp = 0;
if (cellBuffer[currentCell] != null)
{ {
var tmp = 0;
if (EqualCellsBitstreamSize > 0) if (EqualCellsBitstreamSize > 0)
tmp = ec.GetBit(); tmp = ec.GetBit();
@ -287,65 +289,67 @@ namespace OpenDiablo2.Common.Models
} }
else pixelMask = 0x0F; else pixelMask = 0x0F;
if (nextCell)
continue;
if (nextCell == false) // Decode the pixels
var pixelStack = new UInt32[4];
lastPixel = 0;
int numberOfPixelBits = pixelMaskLookup[pixelMask];
var encodingType = ((numberOfPixelBits != 0) && (EncodingTypeBitsreamSize > 0))
? et.GetBit()
: 0;
int decodedPixel = 0;
for (int i = 0; i < numberOfPixelBits; i++)
{ {
// Decode the pixels if (encodingType != 0)
UInt32[] pixelStack = new UInt32[4];
int numberOfPixelBits = pixelMaskLookup[pixelMask];
var encodingType = ((numberOfPixelBits != 0) && (EncodingTypeBitsreamSize > 0))
? et.GetBit()
: 0;
int decodedPixel = 0;
for (int i = 0; i < numberOfPixelBits; i++)
{ {
if (encodingType != 0) pixelStack[i] = (UInt32)rp.GetBits(8);
}
else
{
pixelStack[i] = lastPixel;
var pixelDisplacement = pcd.GetBits(4);
pixelStack[i] += (UInt32)pixelDisplacement;
while (pixelDisplacement == 15)
{ {
pixelStack[i] = (UInt32)rp.GetBits(8); pixelDisplacement = pcd.GetBits(4);
}
else
{
pixelStack[i] = lastPixel;
var pixelDisplacement = pcd.GetBits(4);
pixelStack[i] += (UInt32)pixelDisplacement; pixelStack[i] += (UInt32)pixelDisplacement;
while (pixelDisplacement == 15)
{
pixelDisplacement = pcd.GetBits(4);
pixelStack[i] += (UInt32)pixelDisplacement;
}
}
if (pixelStack[i] == lastPixel)
{
pixelStack[i] = 0;
i = numberOfPixelBits; // Just break here....
}
else
{
lastPixel = pixelStack[i];
decodedPixel++;
} }
} }
if (pixelStack[i] == lastPixel)
var oldEntry = cellBuffer[currentCell];
var curIdx = decodedPixel - 1;
var newEntry = new PixelBufferEntry { Value = new byte[4] };
for (int i = 0; i < 4; i++)
{ {
if ((pixelMask * (1 << i)) != 0) pixelStack[i] = 0;
{ i = numberOfPixelBits; // Just break here....
if (curIdx >= 0) }
newEntry.Value[i] = (byte)pixelStack[curIdx--]; else
else {
newEntry.Value[i] = 0; lastPixel = pixelStack[i];
} decodedPixel++;
else
newEntry.Value[i] = PixelBuffer[oldEntry].Value[i];
} }
newEntry.Frame = frameIndex;
newEntry.FrameCellIndex = XOffsetBits + (cellY * HorizontalCellCount);
PixelBuffer.Add(newEntry);
cellBuffer[currentCell] = PixelBuffer.Count() - 1;
} }
var oldEntry = cellBuffer[currentCell];
pbIndex++;
var newEntry = PixelBuffer[pbIndex];
var curIdx = decodedPixel - 1;
for (int i = 0; i < 4; i++)
{
if ((pixelMask & (1 << i)) != 0)
{
if (curIdx >= 0)
newEntry.Value[i] = (byte)pixelStack[curIdx--];
else
newEntry.Value[i] = 0;
}
else
newEntry.Value[i] = oldEntry.Value[i];
}
cellBuffer[currentCell] = newEntry;
newEntry.Frame = frameIndex;
newEntry.FrameCellIndex = cellX + (cellY * HorizontalCellCount);
} }
} }
} }