public void Build_SequentialArranger() { var codecFactory = new CodecFactory(new()); var memorySource = new MemoryDataSource("TestMemoryFile", 2 * 256 * 512); SequentialArranger arranger = ArrangerBuilder .WithSingleLayout() .WithElementPixelSize(256, 512) .WithPixelColorType(PixelColorType.Direct) .WithName("SequentialTestArranger") .AsSequentialArranger(codecFactory) .WithDataFile(memorySource) .WithCodecName("PSX 16bpp") .Build(); Assert.That(arranger.Layout == ElementLayout.Single); Assert.That(arranger.ArrangerElementSize == new Size(1, 1)); Assert.That(arranger.ElementPixelSize == new Size(256, 512)); Assert.That(arranger.ColorType == PixelColorType.Direct); Assert.That(arranger.Name == "SequentialTestArranger"); Assert.That(arranger.ActiveCodec.Name == "PSX 16bpp"); Assert.That(arranger.ActiveCodec.ColorType == PixelColorType.Direct); Assert.That(arranger.ActiveCodec.Layout == ImageLayout.Single); Assert.That(arranger.ActiveCodec.Width == 256); Assert.That(arranger.ActiveCodec.Height == 512); Assert.That(arranger.ActivePalette is null); Assert.That(arranger.ActiveDataSource.Name == "TestMemoryFile"); }
/// <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); }