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); }
public MagitekResult AddScatteredArranger(ScatteredArrangerModel arrangerModel, string parentNodePath, string fileLocation) { var arranger = new ScatteredArranger(arrangerModel.Name, arrangerModel.ColorType, arrangerModel.Layout, arrangerModel.ArrangerElementSize.Width, arrangerModel.ArrangerElementSize.Height, arrangerModel.ElementPixelSize.Width, arrangerModel.ElementPixelSize.Height); for (int x = 0; x < arrangerModel.ElementGrid.GetLength(0); x++) { for (int y = 0; y < arrangerModel.ElementGrid.GetLength(1); y++) { var result = CreateElement(arrangerModel, x, y); if (result.IsT0) { arranger.SetElement(result.AsT0.Result, x, y); } else if (result.IsT1) { return(new MagitekResult.Failed(result.AsT1.Reason)); } } } var arrangerNode = new ArrangerNode(arranger.Name, arranger) { DiskLocation = fileLocation, Model = arrangerModel }; Tree.TryGetNode(parentNodePath, out var parentNode); parentNode.AttachChildNode(arrangerNode); return(MagitekResult.SuccessResult); }
/// <summary> /// Copies elements from the source into specified destination ScatteredArranger /// </summary> /// <param name="source"></param> /// <param name="dest"></param> /// <param name="sourceStart">Starting point of source arranger in element coordinates</param> /// <param name="destStart">Starting point of destination arranger in element coordinates</param> /// <param name="copyWidth">Width of copy in elements</param> /// <param name="copyHeight">Height of copy in elements</param> public static MagitekResult CopyElements(ElementCopy source, ScatteredArranger dest, Point sourceStart, Point destStart, int copyWidth, int copyHeight) { var result = CanCopyElements(source, dest, sourceStart, destStart, copyWidth, copyHeight); if (result.Value is MagitekResult.Success) { CopyElementsInternal(source, dest, sourceStart, destStart, copyWidth, copyHeight); } return(result);
public static ScatteredArrangerModel MapToModel(this ScatteredArranger arranger, Dictionary <IProjectResource, string> resourceMap) { var model = new ScatteredArrangerModel() { Name = arranger.Name, ArrangerElementSize = arranger.ArrangerElementSize, ElementPixelSize = arranger.ElementPixelSize, Layout = arranger.Layout, ColorType = arranger.ColorType }; model.ElementGrid = new ArrangerElementModel[model.ArrangerElementSize.Width, model.ArrangerElementSize.Height]; for (int x = 0; x < model.ElementGrid.GetLength(0); x++) { for (int y = 0; y < model.ElementGrid.GetLength(1); y++) { if (arranger.GetElement(x, y) is ArrangerElement el) { model.ElementGrid[x, y] = MapToModel(el, x, y); } } } return(model); ArrangerElementModel MapToModel(ArrangerElement el, int elemX, int elemY) { var model = new ArrangerElementModel { FileAddress = el.SourceAddress, PositionX = elemX, PositionY = elemY, CodecName = el.Codec.Name, Mirror = el.Mirror, Rotation = el.Rotation }; if (el.Source is not null && resourceMap.TryGetValue(el.Source, out var dataFileKey)) { model.DataFileKey = dataFileKey; } if (el.Palette is not null && resourceMap.TryGetValue(el.Palette, out var paletteKey)) { model.PaletteKey = paletteKey; } return(model); } }
static void CopyElementsInternal(ElementCopy source, ScatteredArranger dest, Point sourceStart, Point destStart, int copyWidth, int copyHeight) { for (int y = 0; y < copyHeight; y++) { for (int x = 0; x < copyWidth; x++) { var el = source.Elements[x + sourceStart.X, y + sourceStart.Y]; if (el is ArrangerElement element) { dest.SetElement(element, x + destStart.X, y + destStart.Y); } } } }
/// <summary> /// Adds the specified resource to the parent resource node /// </summary> /// <param name="parentNode">ResourceNode that is contained by the project</param> /// <param name="resource">New resource to add</param> /// <returns>The added resource node result</returns> public virtual MagitekResult <ResourceNode> AddResource(ResourceNode parentNode, IProjectResource resource) { var tree = _projects.FirstOrDefault(x => x.ContainsNode(parentNode)); if (tree is null) { return(new MagitekResult <ResourceNode> .Failed($"{parentNode.Item.Name} is not contained within any loaded project")); } if (parentNode.ContainsChildNode(resource.Name)) { return(new MagitekResult <ResourceNode> .Failed($"'{parentNode.Name}' already contains a child named '{resource.Name}'")); } else if (parentNode.Item.CanContainChildResources == false) { return(new MagitekResult <ResourceNode> .Failed($"'{parentNode.Name}' cannot contain children")); } try { ResourceNode childNode = resource switch { DataSource df => new DataFileNode(df.Name, df), ScatteredArranger arranger => new ArrangerNode(arranger.Name, arranger), Palette pal => new PaletteNode(pal.Name, pal), ResourceFolder folder => new ResourceFolderNode(folder.Name, folder), _ => null }; if (childNode is null) { return(new MagitekResult <ResourceNode> .Failed($"Cannot add a resource of type '{resource.GetType()}'")); } var contents = _serializerFactory.CreateWriter(tree).SerializeResource(childNode); var location = ResourceFileLocator.LocateByParent(tree, parentNode, childNode); File.WriteAllText(location, contents); parentNode.AttachChildNode(childNode); childNode.DiskLocation = location; UpdateNodeModel(tree, childNode); return(new MagitekResult <ResourceNode> .Success(childNode)); } catch (Exception ex) { return(new MagitekResult <ResourceNode> .Failed(ex.Message)); } }
public void ScatteredArranger_Reversibility_CanReverse(ScatteredArranger arranger, string imageFileName) { var exportedImageFileName = $"test.png"; var indexedImage = new IndexedImage(arranger); indexedImage.ImportImage(imageFileName, new ImageSharpFileAdapter(), ColorMatchStrategy.Exact); indexedImage.ExportImage(exportedImageFileName, new ImageSharpFileAdapter()); using var expected = Image <Rgba32> .Load <Rgba32>(imageFileName); using var actual = Image <Rgba32> .Load <Rgba32>(exportedImageFileName); ImageRgba32Assert.AreEqual(expected, actual); }
public void Build_ScatteredArranger() { ScatteredArranger arranger = ArrangerBuilder .WithTiledLayout() .WithArrangerElementSize(8, 16) .WithElementPixelSize(8, 8) .WithPixelColorType(PixelColorType.Indexed) .WithName("ScatteredTestArranger") .AsScatteredArranger() .Build(); Assert.That(arranger.Layout == ElementLayout.Tiled); Assert.That(arranger.ArrangerElementSize == new Size(8, 16)); Assert.That(arranger.ElementPixelSize == new Size(8, 8)); Assert.That(arranger.ColorType == PixelColorType.Indexed); Assert.That(arranger.Name == "ScatteredTestArranger"); }
public void Setup() { _df = new MemoryDataSource("MemoryDataSource"); _sourceIndexed = new ScatteredArranger("source", PixelColorType.Indexed, ElementLayout.Tiled, 6, 6, 8, 8); for (int y = 0; y < _sourceIndexed.ArrangerElementSize.Height; y++) { for (int x = 0; x < _sourceIndexed.ArrangerElementSize.Width; x++) { if (_sourceIndexed.GetElement(x, y) is ArrangerElement element) { element = element.WithTarget(_df, new BitAddress(x * y), new Snes3bppCodec(8, 8), null); _sourceIndexed.SetElement(element, x, y); } } } }
public override DataTemplate SelectTemplate(object item, DependencyObject container) { if (item == null || container is null) { return(null); } if (item is ResourceChangeViewModel changeVm) { return(changeVm.Resource switch { ResourceFolder _ => FolderNodeTemplate, DataSource _ => DataFileNodeTemplate, ScatteredArranger _ => ArrangerNodeTemplate, Palette _ => PaletteNodeTemplate, _ => throw new ArgumentException($"{nameof(SelectTemplate)} does not contain a template for type {changeVm.Resource.GetType()}") });
/// <summary> /// Tests if the source can be copied into the specified destination ScatteredArranger /// </summary> /// <param name="source"></param> /// <param name="dest"></param> /// <param name="destStart">Upper-left point to begin copying into in element coordinates</param> /// <returns></returns> public static MagitekResult CanCopyElements(ElementCopy source, ScatteredArranger dest, Point sourceStart, Point destStart, int copyWidth, int copyHeight) { if (copyWidth > dest.ArrangerElementSize.Width - destStart.X) { return(new MagitekResult.Failed($"Destination arranger '{dest.Name}' with width ({dest.ArrangerElementSize.Width}) is insufficient to copy {copyWidth} elements starting from position {destStart.X}")); } if (copyHeight > dest.ArrangerElementSize.Height - destStart.Y) { return(new MagitekResult.Failed($"Destination arranger '{dest.Name}' with height ({dest.ArrangerElementSize.Height}) is insufficient to copy {copyHeight} elements starting from position {destStart.Y}")); } if (copyWidth > source.Width - sourceStart.X) { return(new MagitekResult.Failed($"Source copy with width ({source.Width}) is insufficient to copy {copyWidth} elements starting from position {sourceStart.X}")); } if (copyHeight > source.Height - sourceStart.Y) { return(new MagitekResult.Failed($"Source copy with height ({source.Height}) is insufficient to copy {copyHeight} elements starting from position {sourceStart.Y}")); } if (source.Source.ElementPixelSize != dest.ElementPixelSize) { return(new MagitekResult.Failed($"Source arranger '{source.Source.Name}' with element size ({source.Source.ElementPixelSize.Width}, {source.Source.ElementPixelSize.Height}) does not match destination arranger '{dest.Name}' with element size ({dest.ElementPixelSize.Width}, {dest.ElementPixelSize.Height})")); } if (dest.Layout != ElementLayout.Tiled && (copyWidth != 1 || copyHeight != 1)) { return(new MagitekResult.Failed($"Destination arranger '{dest.Name}' is not a tiled layout")); } if (source.Source.ColorType != dest.ColorType) { return(new MagitekResult.Failed($"Source arranger '{source.Source.Name}' ColorType {source.Source.ColorType} does not match destination arranger ColorType {dest.ColorType}")); } return(MagitekResult.SuccessResult); }
public void Setup(string dataFileName, string arrangerName) { using (var fs = File.Create(dataFileName)) { Random rng = new Random(); var data = new byte[3 * 16 * 32]; rng.NextBytes(data); fs.Write(data); } _df = new FileDataSource("FileSource", Path.GetFullPath(dataFileName)); _arranger = new ScatteredArranger(arrangerName, PixelColorType.Indexed, ElementLayout.Tiled, 16, 32, 8, 8); for (int y = 0; y < _arranger.ArrangerElementSize.Height; y++) { for (int x = 0; x < _arranger.ArrangerElementSize.Width; x++) { var el = new ArrangerElement(x * 8, y * 8, _df, new BitAddress(24 * x + 24 * x * y), _codec, _pal); _arranger.SetElement(el, x, y); } } }
/// <summary> /// Private method for cloning an Arranger /// </summary> /// <param name="posX">Left edge of Arranger in pixel coordinates</param> /// <param name="posY">Top edge of Arranger in pixel coordinates</param> /// <param name="width">Width of Arranger in pixels</param> /// <param name="height">Height of Arranger in pixels</param> /// <returns></returns> protected override Arranger CloneArrangerCore(int posX, int posY, int width, int height) { var elemX = posX / ElementPixelSize.Width; var elemY = posY / ElementPixelSize.Height; var elemsWidth = (width + ElementPixelSize.Width - 1) / ElementPixelSize.Width; var elemsHeight = (height + ElementPixelSize.Height - 1) / ElementPixelSize.Height; var arranger = new ScatteredArranger(Name, ColorType, Layout, elemsWidth, elemsHeight, ElementPixelSize.Width, ElementPixelSize.Height); for (int y = 0; y < elemsHeight; y++) { for (int x = 0; x < elemsWidth; x++) { var el = ElementGrid[y + elemY, x + elemX]?.WithLocation(x * ElementPixelSize.Width, y * ElementPixelSize.Height); if (el is ArrangerElement element) { arranger.SetElement(element, x, y); } } } return(arranger); }
public ArrangerNode(string nodeName, ScatteredArranger resource) : base(nodeName, resource) { }