Example #1
0
    private void WriteFileColor(DataSource df, BitAddress offset, IColor foreignColor, Endian endian)
    {
        Span <byte> colorBuffer = stackalloc byte[4];

        int writeSize = (foreignColor.Size + 7) / 8;

        if (writeSize == 1)
        {
            colorBuffer[0] = (byte)foreignColor.Color;
        }
        else if (writeSize == 2 && endian == Endian.Little)
        {
            BinaryPrimitives.WriteUInt16LittleEndian(colorBuffer, (ushort)foreignColor.Color);
        }
        else if (writeSize == 2 && endian == Endian.Big)
        {
            BinaryPrimitives.WriteUInt16BigEndian(colorBuffer, (ushort)foreignColor.Color);
        }
        else if (writeSize == 3)
        {
            colorBuffer[0] = (byte)foreignColor.Color;
            colorBuffer[1] = (byte)(foreignColor.Color >> 8);
            colorBuffer[2] = (byte)(foreignColor.Color >> 16);
        }
        else if (writeSize == 4 && endian == Endian.Little)
        {
            BinaryPrimitives.WriteUInt32LittleEndian(colorBuffer, foreignColor.Color);
        }
        else if (writeSize == 4 && endian == Endian.Big)
        {
            BinaryPrimitives.WriteUInt32BigEndian(colorBuffer, foreignColor.Color);
        }

        df.Write(offset, colorBuffer[..writeSize]);
Example #2
0
    public static ScatteredArranger CreateIndexedArrangerFromImage(string imageFile, ColorModel colorModel,
                                                                   bool zeroIndexTransparent, ICodecFactory factory, IGraphicsCodec codec)
    {
        var image        = new Bitmap(imageFile);
        var imagePalette = image.Palette;

        var palette      = new Palette("testPalette", new ColorFactory(), colorModel, zeroIndexTransparent, PaletteStorageSource.Project);
        var colorSources = imagePalette.Entries
                           .Select(x => new ProjectNativeColorSource(new ColorRgba32(x.R, x.G, x.B, x.A)));

        palette.SetColorSources(colorSources);

        var file   = new MemoryDataSource("test", image.Width * image.Height);
        var elemsX = image.Width / codec.Width;
        var elemsY = image.Height / codec.Height;

        var arranger = new ScatteredArranger("testArranger", PixelColorType.Indexed, ElementLayout.Tiled, elemsX, elemsY, codec.Width, codec.Height);

        var address = new BitAddress(0);

        for (int y = 0; y < elemsY; y++)
        {
            for (int x = 0; x < elemsX; x++)
            {
                var element = new ArrangerElement(x, y, file, address, factory.CloneCodec(codec), palette);
                address += codec.StorageSize;

                arranger.SetElement(element, x, y);
            }
        }

        return(arranger);
    }
Example #3
0
    public static async ValueTask <byte[]> ReadUnshiftedAsync(this Stream stream, BitAddress address, int readBits)
    {
        var readBuffer = new byte[(readBits + address.BitOffset + 7) / 8];
        await stream.ReadUnshiftedAsync(address, readBits, readBuffer);

        return(readBuffer);
    }
Example #4
0
    public void ReadShifted_AsExpected(byte[] data, BitAddress offset, int numBits, byte[] expected)
    {
        var stream = new MemoryStream(data);
        var actual = new byte[(numBits + 7) / 8];

        stream.ReadShifted(offset, numBits, actual);

        CollectionAssert.AreEqual(expected, actual);
    }
Example #5
0
 public ArrangerElement(int x1, int y1, DataSource dataFile, BitAddress address, IGraphicsCodec codec, Palette palette)
 {
     X1            = x1;
     Y1            = y1;
     Source        = dataFile;
     SourceAddress = address;
     Codec         = codec;
     Palette       = palette;
     Mirror        = MirrorOperation.None;
     Rotation      = RotationOperation.None;
 }
Example #6
0
    public void WriteShifted_AsExpected(byte[] data, BitAddress offset, int numBits, byte[] writeData, byte[] expected)
    {
        using var stream = new MemoryStream(data);
        stream.WriteShifted(offset, numBits, writeData);

        stream.Seek(0, SeekOrigin.Begin);
        var actual = new byte[expected.Length];

        stream.Read(actual);

        CollectionAssert.AreEqual(expected, actual);
    }
Example #7
0
    /// <summary>
    ///
    /// </summary>
    /// <param name="df">Source to read color from</param>
    /// <param name="offset">Offset into the source to read from</param>
    /// <param name="colorModel">Model to create the color with</param>
    /// <param name="size">Read size in bits</param>
    /// <param name="endian">Endianness of the color</param>
    /// <returns>The ColorModel-mapped color</returns>
    /// <exception cref="NotSupportedException">Size must be 32 bits or less</exception>
    private IColor ReadFileColor(DataSource df, BitAddress offset, ColorModel colorModel, int size, Endian endian)
    {
        Span <byte> colorBuffer = stackalloc byte[4];

        int readSize = (size + 7) / 8;

        df.Read(offset, size, colorBuffer);

        uint readColor;

        if (readSize == 1)
        {
            readColor = colorBuffer[0];
        }
        else if (readSize == 2 && endian == Endian.Little)
        {
            readColor = BinaryPrimitives.ReadUInt16LittleEndian(colorBuffer);
        }
        else if (readSize == 2 && endian == Endian.Big)
        {
            readColor = BinaryPrimitives.ReadUInt16BigEndian(colorBuffer);
        }
        else if (readSize == 3)
        {
            readColor  = colorBuffer[0];
            readColor |= ((uint)colorBuffer[1]) << 8;
            readColor |= ((uint)colorBuffer[2]) << 16;
        }
        else if (readSize == 4 && endian == Endian.Little)
        {
            readColor = BinaryPrimitives.ReadUInt32LittleEndian(colorBuffer);
        }
        else if (readSize == 4 && endian == Endian.Big)
        {
            readColor = BinaryPrimitives.ReadUInt32BigEndian(colorBuffer);
        }
        else
        {
            throw new NotSupportedException($"{nameof(LoadColors)}: Palette formats with entry sizes larger than 4 bytes are not supported");
        }

        return(_colorFactory.CreateColor(colorModel, readColor));
    }
Example #8
0
    /// <summary>
    /// Moves the sequential arranger's top-left element to the specified address with the remaining elements following
    /// If the arranger will overflow the file, then seek only to the furthest offset
    /// </summary>
    /// <param name="absoluteAddress">Specified address to move the arranger to</param>
    /// <returns></returns>
    public BitAddress Move(BitAddress absoluteAddress)
    {
        if (Mode != ArrangerMode.Sequential)
        {
            throw new InvalidOperationException($"{nameof(Move)}: Arranger {Name} is not in sequential mode");
        }

        var testaddress = absoluteAddress + ArrangerBitSize; // Tests the bounds of the arranger vs the file size

        if (FileSize * 8 < ArrangerBitSize)                  // Arranger needs more bits than the entire file
        {
            Address = new BitAddress(0, 0);
        }
        else if (testaddress.Offset > FileSize * 8) // Clamp arranger to edge of viewable file
        {
            Address = new BitAddress(FileSize * 8 - ArrangerBitSize);
        }
        else
        {
            Address = absoluteAddress;
        }

        var relativeChange = Address - GetInitialSequentialFileAddress();

        for (int posY = 0; posY < ArrangerElementSize.Height; posY++)
        {
            for (int posX = 0; posX < ArrangerElementSize.Width; posX++)
            {
                var el = GetElement(posX, posY);
                if (el is ArrangerElement element)
                {
                    element = element.WithAddress(element.SourceAddress + relativeChange);
                    ElementGrid[posY, posX] = element;
                }
            }
        }

        return(Address);
    }
Example #9
0
        public string SaveToString()
        {
            var buffer = new string[16];

            buffer[0]  = ((short)Address).ToString(CultureInfo.InvariantCulture);
            buffer[1]  = ((int)SizeType).ToString(CultureInfo.InvariantCulture);
            buffer[2]  = Mul.ToString(CultureInfo.InvariantCulture);
            buffer[3]  = Div.ToString(CultureInfo.InvariantCulture);
            buffer[4]  = Offset.ToString(CultureInfo.InvariantCulture);
            buffer[5]  = Precision.ToString(CultureInfo.InvariantCulture);
            buffer[6]  = ((int)ItemType).ToString(CultureInfo.InvariantCulture);
            buffer[7]  = ColCount.ToString(CultureInfo.InvariantCulture);
            buffer[8]  = RowCount.ToString(CultureInfo.InvariantCulture);
            buffer[9]  = BitAddress.ToString(CultureInfo.InvariantCulture);
            buffer[10] = Reserve1.ToString(CultureInfo.InvariantCulture);
            buffer[11] = Reserve2.ToString(CultureInfo.InvariantCulture);
            buffer[12] = ReverseX ? "1" : "0";
            buffer[13] = ReverseY ? "1" : "0";
            buffer[14] = Min.ToString(CultureInfo.InvariantCulture);
            buffer[15] = Max.ToString(CultureInfo.InvariantCulture);

            return(String.Join(" ", buffer));
        }
Example #10
0
 public static async ValueTask WriteUnshiftedAsync(this Stream stream, BitAddress address, int writeBits, ReadOnlyMemory <byte> writeBuffer)
 {
     stream.Seek(address.ByteOffset, SeekOrigin.Begin);
     await stream.WriteUnshiftedAsync(address.BitOffset, writeBits, writeBuffer);
 }
Example #11
0
    /// <summary>
    /// Moves a Sequential Arranger's file position and updates each Element
    /// Will not move outside of the bounds of the underlying file
    /// </summary>
    /// <param name="moveType">Type of move requested</param>
    /// <returns>Updated address of first element</returns>
    public static BitAddress Move(this SequentialArranger arranger, ArrangerMoveType moveType)
    {
        if (arranger.Mode != ArrangerMode.Sequential)
        {
            throw new InvalidOperationException($"{nameof(Move)}: Arranger {arranger.Name} is not in sequential mode");
        }

        var  initialAddress = arranger.Address;
        var  newAddress     = initialAddress;
        long bitDelta       = 0;

        var patternWidth  = arranger.TileLayout?.Width ?? 1;
        var patternHeight = arranger.TileLayout?.Height ?? 1;

        switch (moveType) // Calculate the new address based on the movement command. Negative and post-EOF addresses are handled after the switch
        {
        case ArrangerMoveType.ByteDown:
            newAddress += 8;
            break;

        case ArrangerMoveType.ByteUp:
            newAddress -= 8;
            break;

        case ArrangerMoveType.RowDown:
            if (arranger.Layout == ElementLayout.Tiled)
            {
                bitDelta = arranger.ArrangerElementSize.Width * arranger.ActiveCodec.StorageSize * patternHeight;
            }
            else if (arranger.Layout == ElementLayout.Single)
            {
                bitDelta = arranger.ActiveCodec.StorageSize / arranger.ArrangerPixelSize.Height;
            }

            newAddress += bitDelta;
            break;

        case ArrangerMoveType.RowUp:
            if (arranger.Layout == ElementLayout.Tiled)
            {
                bitDelta = arranger.ArrangerElementSize.Width * arranger.ActiveCodec.StorageSize * patternHeight;
            }
            else if (arranger.Layout == ElementLayout.Single)
            {
                bitDelta = arranger.ActiveCodec.StorageSize / arranger.ArrangerPixelSize.Height;
            }
            newAddress -= bitDelta;
            break;

        case ArrangerMoveType.ColRight:
            if (arranger.Layout == ElementLayout.Tiled)
            {
                bitDelta = arranger.ActiveCodec.StorageSize * patternWidth * patternHeight;
            }
            else if (arranger.Layout == ElementLayout.Single)
            {
                bitDelta = 16 * arranger.ActiveCodec.StorageSize * arranger.ActiveCodec.Height / arranger.ActiveCodec.Width;
            }
            newAddress += bitDelta;
            break;

        case ArrangerMoveType.ColLeft:
            if (arranger.Layout == ElementLayout.Tiled)
            {
                bitDelta = arranger.ActiveCodec.StorageSize * patternWidth * patternHeight;
            }
            else if (arranger.Layout == ElementLayout.Single)
            {
                bitDelta = 16 * arranger.ActiveCodec.StorageSize * arranger.ActiveCodec.Height / arranger.ActiveCodec.Width;
            }
            newAddress -= bitDelta;
            break;

        case ArrangerMoveType.PageDown:
            if (arranger.Layout == ElementLayout.Tiled)
            {
                bitDelta = arranger.ArrangerElementSize.Width * arranger.ActiveCodec.StorageSize * arranger.ArrangerElementSize.Height / 2;
            }
            else if (arranger.Layout == ElementLayout.Single)
            {
                bitDelta = arranger.ActiveCodec.StorageSize / 2;
            }
            newAddress += bitDelta;
            break;

        case ArrangerMoveType.PageUp:
            if (arranger.Layout == ElementLayout.Tiled)
            {
                bitDelta = arranger.ArrangerElementSize.Width * arranger.ActiveCodec.StorageSize * arranger.ArrangerElementSize.Height / 2;
            }
            else if (arranger.Layout == ElementLayout.Single)
            {
                bitDelta = arranger.ActiveCodec.StorageSize / 2;
            }
            newAddress -= bitDelta;
            break;

        case ArrangerMoveType.Home:
            newAddress = BitAddress.Zero;
            break;

        case ArrangerMoveType.End:
            newAddress = new BitAddress(arranger.FileSize * 8 - arranger.ArrangerBitSize);
            break;
        }

        var maxAddress = new BitAddress(arranger.FileSize * 8 - arranger.ArrangerBitSize);

        if (maxAddress.Offset < 0)
        {
            maxAddress = BitAddress.Zero;
        }

        newAddress = new BitAddress(Math.Clamp(newAddress.Offset, 0, maxAddress.Offset));

        if (initialAddress != newAddress)
        {
            newAddress = arranger.Move(newAddress);
        }

        return(newAddress);
    }
Example #12
0
 public virtual async Task WriteAsync(BitAddress address, int writeBits, ReadOnlyMemory <byte> buffer) =>
 await _stream.Value.WriteUnshiftedAsync(address, writeBits, buffer);
Example #13
0
 public virtual void Write(BitAddress address, int writeBits, ReadOnlySpan <byte> buffer) =>
 _stream.Value.WriteUnshifted(address, writeBits, buffer);
Example #14
0
 public virtual async ValueTask ReadAsync(BitAddress address, int readBits, Memory <byte> buffer) =>
 await _stream.Value.ReadUnshiftedAsync(address, readBits, buffer);
Example #15
0
 public virtual async ValueTask <byte[]> ReadAsync(BitAddress address, int readBits) =>
 await _stream.Value.ReadUnshiftedAsync(address, readBits);
Example #16
0
 public virtual void Read(BitAddress address, int readBits, Span <byte> buffer) =>
 _stream.Value.ReadUnshifted(address, readBits, buffer);
Example #17
0
 public static async ValueTask ReadUnshiftedAsync(this Stream stream, BitAddress address, int readBits, Memory <byte> buffer)
 {
     stream.Seek(address.ByteOffset, SeekOrigin.Begin);
     await stream.ReadUnshiftedAsync(address, readBits, buffer);
 }
Example #18
0
 public override int GetHashCode()
 {
     return((int)Domain * 17 ^ BitAddress.GetHashCode() ^ BitSize.GetHashCode());
 }
Example #19
0
 public void SetAddressStr()
 {
     WordAddressStr = WordAddress.ToString().PadLeft(4, '0');
     BitAddressStr  = BitAddress.ToString().PadLeft(2, '0');
 }
Example #20
0
 public FileColorSourceModel(BitAddress fileAddress, int entries, Endian endian)
 {
     FileAddress = fileAddress;
     Entries     = entries;
     Endian      = endian;
 }
Example #21
0
 public FileColorSource(BitAddress offset, Endian endian)
 {
     Offset = offset;
     Endian = endian;
 }
Example #22
0
 public virtual byte[] Read(BitAddress address, int readBits) =>
 _stream.Value.ReadUnshifted(address, readBits);