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> /// Returns the enumeration of a subsection of Elements in the grid in a left-to-right, row-by-row order /// </summary> /// <param name="elemX">Starting x-coordinate in element coordinates</param> /// <param name="elemY">Starting y-coordinate in element coordinates</param> /// <param name="width">Number of elements to enumerate in x-direction</param> /// <param name="height">Number of elements to enumerate in y-direction</param> /// <returns></returns> public static IEnumerable <ArrangerElementModel> EnumerateElements(this ScatteredArrangerModel model, int elemX, int elemY, int width, int height) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { yield return(model.ElementGrid[x + elemX, y + elemY]); } } }
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); } }
private MagitekResult <ArrangerElement?> CreateElement(ScatteredArrangerModel arrangerModel, int x, int y) { var elementModel = arrangerModel.ElementGrid[x, y]; IGraphicsCodec codec = default; Palette palette = default; DataSource df = default; var address = BitAddress.Zero; if (elementModel is null) { return(new MagitekResult <ArrangerElement?> .Success(null)); } else if (arrangerModel.ColorType == PixelColorType.Indexed) { if (!string.IsNullOrWhiteSpace(elementModel.DataFileKey)) { Tree.TryGetItem <DataSource>(elementModel.DataFileKey, out df); } address = elementModel.FileAddress; var paletteKey = elementModel.PaletteKey; palette = ResolvePalette(paletteKey); if (palette is null) { return(new MagitekResult <ArrangerElement?> .Failed($"Could not resolve palette '{paletteKey}' referenced by arranger '{arrangerModel.Name}'")); } codec = _codecFactory.GetCodec(elementModel.CodecName, new Size(arrangerModel.ElementPixelSize.Width, arrangerModel.ElementPixelSize.Height)); } else if (arrangerModel.ColorType == PixelColorType.Direct) { if (!string.IsNullOrWhiteSpace(elementModel.DataFileKey)) { Tree.TryGetItem <DataSource>(elementModel.DataFileKey, out df); } address = elementModel.FileAddress; codec = _codecFactory.GetCodec(elementModel.CodecName, new Size(arrangerModel.ElementPixelSize.Width, arrangerModel.ElementPixelSize.Height)); } else { return(new MagitekResult <ArrangerElement?> .Failed($"{nameof(CreateElement)}: Arranger '{arrangerModel.Name}' has invalid {nameof(PixelColorType)} '{arrangerModel.ColorType}'")); } var pixelX = x * arrangerModel.ElementPixelSize.Width; var pixelY = y * arrangerModel.ElementPixelSize.Height; var el = new ArrangerElement(pixelX, pixelY, df, address, codec, palette, elementModel.Mirror, elementModel.Rotation); return(new MagitekResult <ArrangerElement?> .Success(el)); }
public static string FindMostFrequentElementPropertyValue(this ScatteredArrangerModel model, Func <ArrangerElementModel, string> selector) { return(EnumerateElements(model) .OfType <ArrangerElementModel>() .Select(selector) .GroupBy(x => x) .Select(group => new { Item = group.Key, Count = group.Count() }) .MaxBy(x => x.Count) ?.Item); }
/// <summary> /// Returns the enumeration of all Elements in the grid in a left-to-right, row-by-row order /// </summary> /// <returns></returns> public static IEnumerable <ArrangerElementModel> EnumerateElements(this ScatteredArrangerModel model) => model.EnumerateElements(0, 0, model.ArrangerElementSize.Width, model.ArrangerElementSize.Height);
private bool TryDeserializeScatteredArranger(XElement element, string resourceName, out ScatteredArrangerModel arrangerModel) { var model = new ScatteredArrangerModel(); model.Name = resourceName; var elementsx = int.Parse(element.Attribute("elementsx").Value); // Width of arranger in elements var elementsy = int.Parse(element.Attribute("elementsy").Value); // Height of arranger in elements var width = int.Parse(element.Attribute("width").Value); // Width of element in pixels var height = int.Parse(element.Attribute("height").Value); // Height of element in pixels var defaultCodecName = element.Attribute("defaultcodec").Value; var defaultDataFileKey = element.Attribute("defaultdatafile").Value; var defaultPaletteKey = element.Attribute("defaultpalette")?.Value ?? _globalDefaultPalette.Name; var layoutName = element.Attribute("layout").Value; var colorType = element.Attribute("color")?.Value ?? "indexed"; var elementList = element.Descendants("element"); if (layoutName == "tiled") { model.Layout = ElementLayout.Tiled; } else if (layoutName == "single") { model.Layout = ElementLayout.Single; } else { throw new XmlException($"Unsupported arranger layout type ('{layoutName}') for arranger '{model.Name}'"); } if (colorType == "indexed") { model.ColorType = PixelColorType.Indexed; } else if (colorType == "direct") { model.ColorType = PixelColorType.Direct; } else { throw new XmlException($"Unsupported pixel color type ('{colorType}') for arranger '{model.Name}'"); } model.ArrangerElementSize = new Size(elementsx, elementsy); model.ElementGrid = new ArrangerElementModel[elementsx, elementsy]; model.ElementPixelSize = new Size(width, height); var xmlElements = elementList.Select(e => new { fileoffset = long.Parse(e.Attribute("fileoffset").Value, System.Globalization.NumberStyles.HexNumber), bitoffset = e.Attribute("bitoffset"), posx = int.Parse(e.Attribute("posx").Value), posy = int.Parse(e.Attribute("posy").Value), format = e.Attribute("codec"), palette = e.Attribute("palette"), datafile = e.Attribute("datafile"), mirror = e.Attribute("mirror"), rotation = e.Attribute("rotation") }); foreach (var xmlElement in xmlElements) { var el = new ArrangerElementModel(); el.DataFileKey = xmlElement.datafile?.Value ?? defaultDataFileKey; el.PaletteKey = xmlElement.palette?.Value ?? defaultPaletteKey; el.CodecName = xmlElement.format?.Value ?? defaultCodecName; el.PositionX = xmlElement.posx; el.PositionY = xmlElement.posy; if (xmlElement.bitoffset is not null) { el.FileAddress = new BitAddress(xmlElement.fileoffset, int.Parse(xmlElement.bitoffset.Value)); } else { el.FileAddress = new BitAddress(xmlElement.fileoffset, 0); } el.Mirror = xmlElement.mirror?.Value switch { "none" => MirrorOperation.None, "horizontal" => MirrorOperation.Horizontal, "vertical" => MirrorOperation.Vertical, "both" => MirrorOperation.Both, _ => MirrorOperation.None }; el.Rotation = xmlElement.rotation?.Value switch { "none" => RotationOperation.None, "left" => RotationOperation.Left, "right" => RotationOperation.Right, "turn" => RotationOperation.Turn, _ => RotationOperation.None }; model.ElementGrid[xmlElement.posx, xmlElement.posy] = el; } arrangerModel = model; return(true); } }