Exemple #1
0
        public MPQDCC(byte[] data, Palette palette)
        {
            var bm = new BitMuncher(data);

            Signature = bm.GetByte();
            if (Signature != 0x74)
            {
                throw new OpenDiablo2Exception("Signature expected to be 0x74 but it is not.");
            }

            Version            = bm.GetByte();
            NumberOfDirections = bm.GetByte();
            FramesPerDirection = bm.GetInt32();

            if (bm.GetInt32() != 1)
            {
                throw new OpenDiablo2Exception("This value isn't 1. It has to be 1.");
            }

            bm.GetInt32(); // TotalSizeCoded
            var directionOffsets = new int[NumberOfDirections];

            for (var i = 0; i < NumberOfDirections; i++)
            {
                directionOffsets[i] = bm.GetInt32();
            }

            Directions = new MPQDCCDirection[NumberOfDirections];
            for (var i = 0; i < NumberOfDirections; i++)
            {
                Directions[i] = new MPQDCCDirection(new BitMuncher(data, directionOffsets[i] * 8), this);
            }
        }
Exemple #2
0
            public MPQDCCDirectionFrame(BitMuncher bits, MPQDCCDirection direction)
            {
                bits.GetBits(direction.Variable0Bits); // Variable0
                Width   = (int)bits.GetBits(direction.WidthBits);
                Height  = (int)bits.GetBits(direction.HeightBits);
                XOffset = bits.GetSignedBits(direction.XOffsetBits);
                YOffset = bits.GetSignedBits(direction.YOffsetBits);
                NumberOfOptionalBytes = (int)bits.GetBits(direction.OptionalDataBits);
                NumberOfCodedBytes    = (int)bits.GetBits(direction.CodedBytesBits);
                FrameIsBottomUp       = bits.GetBit() == 1;

                Box = new Rectangle(
                    XOffset,
                    YOffset - Height + 1,
                    Width,
                    Height
                    );
            }
 public BitMuncher(BitMuncher source)
 {
     this.data   = source.data;
     this.Offset = source.Offset;
 }
Exemple #4
0
            private void FillPixelBuffer(BitMuncher pcd, BitMuncher ec, BitMuncher pm, BitMuncher et, BitMuncher rp)
            {
                UInt32 lastPixel = 0;

                var maxCellX = Frames.Sum(x => x.HorizontalCellCount);
                var maxCellY = Frames.Sum(x => x.VerticalCellCount);

                PixelBuffer = new PixelBufferEntry[maxCellX * maxCellY];
                for (var i = 0; i < maxCellX * maxCellY; i++)
                {
                    PixelBuffer[i] = new PixelBufferEntry {
                        Frame = -1, FrameCellIndex = -1, Value = new byte[4]
                    }
                }
                ;

                var cellBuffer = new PixelBufferEntry[HorizontalCellCount * VerticalCellCount];

                var    frameIndex = -1;
                var    pbIndex    = -1;
                UInt32 pixelMask  = 0x00;

                foreach (var frame in Frames)
                {
                    frameIndex++;
                    var originCellX    = (frame.Box.Left - Box.Left) / 4;
                    var originCellY    = (frame.Box.Top - Box.Top) / 4;
                    var frameCellIndex = 0;
                    for (var cellY = 0; cellY < frame.VerticalCellCount; cellY++)
                    {
                        var currentCellY = cellY + originCellY;
                        for (var cellX = 0; cellX < frame.HorizontalCellCount; cellX++, frameCellIndex++)
                        {
                            var currentCell = originCellX + cellX + (currentCellY * HorizontalCellCount);
                            var nextCell    = false;
                            var tmp         = 0;
                            if (cellBuffer[currentCell] != null)
                            {
                                if (EqualCellsBitstreamSize > 0)
                                {
                                    tmp = (int)ec.GetBit();
                                }
                                else
                                {
                                    tmp = 0;
                                }

                                if (tmp == 0)
                                {
                                    pixelMask = pm.GetBits(4);
                                }
                                else
                                {
                                    nextCell = true;
                                }
                            }
                            else
                            {
                                pixelMask = 0x0F;
                            }

                            if (nextCell)
                            {
                                continue;
                            }

                            // Decode the pixels
                            var pixelStack = new UInt32[4];
                            lastPixel = 0;
                            int numberOfPixelBits = pixelMaskLookup[pixelMask];
                            int encodingType      = 0;
                            if ((numberOfPixelBits != 0) && (EncodingTypeBitsreamSize > 0))
                            {
                                encodingType = (int)et.GetBit();
                            }
                            else
                            {
                                encodingType = 0;
                            }

                            int decodedPixel = 0;
                            for (int i = 0; i < numberOfPixelBits; i++)
                            {
                                if (encodingType != 0)
                                {
                                    pixelStack[i] = rp.GetBits(8);
                                }
                                else
                                {
                                    pixelStack[i] = lastPixel;
                                    var pixelDisplacement = pcd.GetBits(4);
                                    pixelStack[i] += pixelDisplacement;
                                    while (pixelDisplacement == 15)
                                    {
                                        pixelDisplacement = pcd.GetBits(4);
                                        pixelStack[i]    += pixelDisplacement;
                                    }
                                }
                                if (pixelStack[i] == lastPixel)
                                {
                                    pixelStack[i] = 0;
                                    i             = numberOfPixelBits; // Just break here....
                                }
                                else
                                {
                                    lastPixel = pixelStack[i];
                                    decodedPixel++;
                                }
                            }

                            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 * frame.HorizontalCellCount);
                        }
                    }
                }


                // Convert the palette entry index into actual palette entries
                for (var i = 0; i <= pbIndex; i++)
                {
                    for (var x = 0; x < 4; x++)
                    {
                        PixelBuffer[i].Value[x] = PaletteEntries[PixelBuffer[i].Value[x]];
                    }
                }
            }
Exemple #5
0
            private void GenerateFrames(BitMuncher pcd)
            {
                var pbIdx = 0;

                foreach (var cell in Cells)
                {
                    cell.LastWidth  = -1;
                    cell.LastHeight = -1;
                }


                PixelData = new byte[Box.Width * Box.Height];

                var frameIndex = -1;

                foreach (var frame in Frames)
                {
                    frameIndex++;
                    frame.PixelData = new byte[Box.Width * Box.Height];

                    var c = -1;
                    foreach (var cell in frame.Cells)
                    {
                        c++;

                        var cellX      = cell.XOffset / 4;
                        var cellY      = cell.YOffset / 4;
                        var cellIndex  = cellX + (cellY * HorizontalCellCount);
                        var bufferCell = Cells[cellIndex];
                        var pbe        = PixelBuffer[pbIdx];

                        if ((pbe.Frame != frameIndex) || (pbe.FrameCellIndex != c))
                        {
                            // This buffer cell has an EqualCell bit set to 1, so copy the frame cell or clear it
                            if ((cell.Width != bufferCell.LastWidth) || (cell.Height != bufferCell.LastHeight))
                            {
                                // Different sizes
                                /// TODO: Clear the pixels of the frame cell
                                for (int y = 0; y < cell.Height; y++)
                                {
                                    for (int x = 0; x < cell.Width; x++)
                                    {
                                        PixelData[x + cell.XOffset + ((y + cell.YOffset) * frame.Width)] = 0;
                                    }
                                }
                            }
                            else
                            {
                                // Same sizes

                                // Copy the old frame cell into the new position
                                for (var fy = 0; fy < cell.Height; fy++)
                                {
                                    for (var fx = 0; fx < cell.Width; fx++)
                                    {
                                        // Frame (buff.lastx, buff.lasty) -> Frame (cell.offx, cell.offy)
                                        // Cell (0, 0,) ->
                                        // blit(dir->bmp, dir->bmp, buff_cell->last_x0, buff_cell->last_y0, cell->x0, cell->y0, cell->w, cell->h );
                                        PixelData[fx + cell.XOffset + ((fy + cell.YOffset) * Box.Width)]
                                            = PixelData[fx + bufferCell.LastXOffset + ((fy + bufferCell.LastYOffset) * Box.Width)];
                                    }
                                }

                                // Copy it again into the final frame image
                                for (var fy = 0; fy < cell.Height; fy++)
                                {
                                    for (var fx = 0; fx < cell.Width; fx++)
                                    {
                                        // blit(cell->bmp, frm_bmp, 0, 0, cell->x0, cell->y0, cell->w, cell->h );
                                        frame.PixelData[fx + cell.XOffset + ((fy + cell.YOffset) * Box.Width)]
                                            = PixelData[cell.XOffset + fx + ((cell.YOffset + fy) * Box.Width)];
                                    }
                                }
                            }
                        }
                        else
                        {
                            if (pbe.Value[0] == pbe.Value[1])
                            {
                                // Clear the frame
                                //cell.PixelData = new byte[cell.Width * cell.Height];
                                for (var y = 0; y < cell.Height; y++)
                                {
                                    for (var x = 0; x < cell.Width; x++)
                                    {
                                        PixelData[x + cell.XOffset + ((y + cell.YOffset) * Box.Width)] = pbe.Value[0];
                                    }
                                }
                            }
                            else
                            {
                                // Fill the frame cell with the pixels
                                var bitsToRead = (pbe.Value[1] == pbe.Value[2]) ? 1 : 2;

                                for (var y = 0; y < cell.Height; y++)
                                {
                                    for (var x = 0; x < cell.Width; x++)
                                    {
                                        var paletteIndex = pcd.GetBits(bitsToRead);
                                        PixelData[x + cell.XOffset + ((y + cell.YOffset) * Box.Width)] = pbe.Value[paletteIndex];
                                    }
                                }
                            }

                            // Copy the frame cell into the frame
                            for (var fy = 0; fy < cell.Height; fy++)
                            {
                                for (var fx = 0; fx < cell.Width; fx++)
                                {
                                    //blit(cell->bmp, frm_bmp, 0, 0, cell->x0, cell->y0, cell->w, cell->h );
                                    frame.PixelData[fx + cell.XOffset + ((fy + cell.YOffset) * Box.Width)]
                                        = PixelData[fx + cell.XOffset + ((fy + cell.YOffset) * Box.Width)];
                                }
                            }
                            pbIdx++;
                        }

                        bufferCell.LastWidth  = cell.Width;
                        bufferCell.LastHeight = cell.Height;

                        bufferCell.LastXOffset = cell.XOffset;
                        bufferCell.LastYOffset = cell.YOffset;
                    }

                    // Free up the stuff we no longer need
                    frame.Cells = null;
                }

                Cells     = null;
                PixelData = null;
            }
Exemple #6
0
            public MPQDCCDirection(BitMuncher bm, MPQDCC file)
            {
                OutSizeCoded     = (int)bm.GetUInt32();
                CompressionFlags = (int)bm.GetBits(2);
                Variable0Bits    = crazyBitTable[bm.GetBits(4)];
                WidthBits        = crazyBitTable[bm.GetBits(4)];
                HeightBits       = crazyBitTable[bm.GetBits(4)];
                XOffsetBits      = crazyBitTable[bm.GetBits(4)];
                YOffsetBits      = crazyBitTable[bm.GetBits(4)];
                OptionalDataBits = crazyBitTable[bm.GetBits(4)];
                CodedBytesBits   = crazyBitTable[bm.GetBits(4)];

                Frames = new MPQDCCDirectionFrame[file.FramesPerDirection];

                var minx = long.MaxValue;
                var miny = long.MaxValue;
                var maxx = long.MinValue;
                var maxy = long.MinValue;

                // Load the frame headers
                for (var frameIdx = 0; frameIdx < file.FramesPerDirection; frameIdx++)
                {
                    Frames[frameIdx] = new MPQDCCDirectionFrame(bm, this);

                    minx = Math.Min(Frames[frameIdx].Box.X, minx);
                    miny = Math.Min(Frames[frameIdx].Box.Y, miny);
                    maxx = Math.Max(Frames[frameIdx].Box.Right, maxx);
                    maxy = Math.Max(Frames[frameIdx].Box.Bottom, maxy);
                }

                Box = new Rectangle
                {
                    X      = (int)minx,
                    Y      = (int)miny,
                    Width  = (int)(maxx - minx),
                    Height = (int)(maxy - miny)
                };

                if (OptionalDataBits > 0)
                {
                    throw new OpenDiablo2Exception("Optional bits in DCC data is not currently supported.");
                }

                if ((CompressionFlags & 0x2) > 0)
                {
                    EqualCellsBitstreamSize = (int)bm.GetBits(20);
                }

                PixelMaskBitstreamSize = (int)bm.GetBits(20);

                if ((CompressionFlags & 0x1) > 0)
                {
                    EncodingTypeBitsreamSize   = (int)bm.GetBits(20);
                    RawPixelCodesBitstreamSize = (int)bm.GetBits(20);
                }


                // PixelValuesKey
                var paletteEntries = new List <bool>();

                for (var i = 0; i < 256; i++)
                {
                    paletteEntries.Add(bm.GetBit() != 0);
                }

                PaletteEntries = new byte[paletteEntries.Count(x => x)];
                var paletteOffset = 0;

                for (var i = 0; i < 256; i++)
                {
                    if (!paletteEntries[i])
                    {
                        continue;
                    }

                    PaletteEntries[paletteOffset++] = (byte)i;
                }


                // HERE BE GIANTS:
                // Because of the way this thing mashes bits together, BIT offset matters
                // here. For example, if you are on byte offset 3, bit offset 6, and
                // the EqualCellsBitstreamSize is 20 bytes, then the next bit stream
                // will be located at byte 23, bit offset 6!

                var equalCellsBitstream = new BitMuncher(bm);

                bm.SkipBits(EqualCellsBitstreamSize);

                var pixelMaskBitstream = new BitMuncher(bm);

                bm.SkipBits(PixelMaskBitstreamSize);

                var encodingTypeBitsream = new BitMuncher(bm);

                bm.SkipBits(EncodingTypeBitsreamSize);

                var rawPixelCodesBitstream = new BitMuncher(bm);

                bm.SkipBits(RawPixelCodesBitstreamSize);

                var pixelCodeandDisplacement = new BitMuncher(bm);

                // Calculate the cells for the direction
                CaculateCells();

                // Caculate the cells for each of the frames
                foreach (var frame in Frames)
                {
                    frame.CalculateCells(this);
                }

                // Fill in the pixel buffer
                FillPixelBuffer(pixelCodeandDisplacement, equalCellsBitstream, pixelMaskBitstream, encodingTypeBitsream, rawPixelCodesBitstream);

                // Generate the actual frame pixel data
                GenerateFrames(pixelCodeandDisplacement);

                // Verify that everything we expected to read was actually read (sanity check)...
                if (equalCellsBitstream.BitsRead != EqualCellsBitstreamSize)
                {
                    throw new OpenDiablo2Exception("Did not read the correct number of bits!");
                }

                if (pixelMaskBitstream.BitsRead != PixelMaskBitstreamSize)
                {
                    throw new OpenDiablo2Exception("Did not read the correct number of bits!");
                }

                if (encodingTypeBitsream.BitsRead != EncodingTypeBitsreamSize)
                {
                    throw new OpenDiablo2Exception("Did not read the correct number of bits!");
                }

                if (rawPixelCodesBitstream.BitsRead != RawPixelCodesBitstreamSize)
                {
                    throw new OpenDiablo2Exception("Did not read the correct number of bits!");
                }

                bm.SkipBits(pixelCodeandDisplacement.BitsRead);
            }