public static MagitekResult TryRotateElement(this Arranger arranger, int elementX, int elementY, RotationOperation rotate) { if (rotate == RotationOperation.None) { return(MagitekResult.SuccessResult); } if (elementX > arranger.ArrangerElementSize.Width || elementY > arranger.ArrangerElementSize.Height) { return(new MagitekResult.Failed($"Location ({elementX}, {elementY}) is outside of the arranger")); } if (arranger.GetElement(elementX, elementY) is ArrangerElement el) { if (el.Width != el.Height) { return(new MagitekResult.Failed("Only square elements may be rotated")); } var newRotation = (el.Rotation, rotate) switch { (RotationOperation.Left, RotationOperation.Left) => RotationOperation.Turn, (RotationOperation.Turn, RotationOperation.Left) => RotationOperation.Right, (RotationOperation.Right, RotationOperation.Left) => RotationOperation.None, (RotationOperation.Left, RotationOperation.Right) => RotationOperation.None, (RotationOperation.Turn, RotationOperation.Right) => RotationOperation.Left, (RotationOperation.Right, RotationOperation.Right) => RotationOperation.Turn, (RotationOperation.Left, RotationOperation.Turn) => RotationOperation.Right, (RotationOperation.Turn, RotationOperation.Turn) => RotationOperation.None, (RotationOperation.Right, RotationOperation.Turn) => RotationOperation.Left, (RotationOperation.None, _) => rotate, (_, RotationOperation.None) => el.Rotation, _ => el.Rotation }; var rotatedElement = el.WithRotation(newRotation); arranger.SetElement(rotatedElement, elementX, elementY); return(MagitekResult.SuccessResult); } return(new MagitekResult.Failed($"No element present at position ({elementX}, {elementY}) to be rotated")); }
/// <summary> /// Creates a copy of an Arranger's ArrangerElements /// </summary> /// <param name="source">Arranger containing the elements to be copied from</param> /// <param name="elementX">Starting x-coordinate of copy in element coordinates</param> /// <param name="elementY">Starting y-coordinate of copy in element coordinates</param> /// <param name="copyWidth">Width of copy in element coordinates</param> /// <param name="copyHeight">Height of copy in element coordinates</param> public ElementCopy(Arranger source, int elementX, int elementY, int copyWidth, int copyHeight) { Source = source; ProjectResource = Source; X = elementX; Y = elementY; Width = copyWidth; Height = copyHeight; ElementPixelWidth = source.ElementPixelSize.Width; ElementPixelHeight = source.ElementPixelSize.Height; Elements = new ArrangerElement?[copyWidth, copyHeight]; for (int y = 0; y < copyHeight; y++) { for (int x = 0; x < copyWidth; x++) { Elements[x, y] = source.GetElement(x + elementX, y + elementY); } } }
public static MagitekResult TryMirrorElement(this Arranger arranger, int elementX, int elementY, MirrorOperation mirror) { if (mirror == MirrorOperation.None) { return(MagitekResult.SuccessResult); } if (arranger.GetElement(elementX, elementY) is ArrangerElement el) { var newMirror = (el.Mirror, mirror) switch { (MirrorOperation.Horizontal, MirrorOperation.Horizontal) => MirrorOperation.None, (MirrorOperation.Vertical, MirrorOperation.Horizontal) => MirrorOperation.Both, (MirrorOperation.Both, MirrorOperation.Horizontal) => MirrorOperation.Vertical, (MirrorOperation.Horizontal, MirrorOperation.Vertical) => MirrorOperation.Both, (MirrorOperation.Vertical, MirrorOperation.Vertical) => MirrorOperation.None, (MirrorOperation.Both, MirrorOperation.Vertical) => MirrorOperation.Horizontal, (MirrorOperation.Horizontal, MirrorOperation.Both) => MirrorOperation.Vertical, (MirrorOperation.Vertical, MirrorOperation.Both) => MirrorOperation.Horizontal, (MirrorOperation.Both, MirrorOperation.Both) => MirrorOperation.None, (MirrorOperation.None, _) => mirror, (_, MirrorOperation.None) => el.Mirror, _ => el.Mirror }; var mirroredElement = el.WithMirror(newMirror); arranger.SetElement(mirroredElement, elementX, elementY); return(MagitekResult.SuccessResult); } return(new MagitekResult.Failed($"No element present at position ({elementX}, {elementY}) to be mirrored")); }
public override void Render() { if (Width <= 0 || Height <= 0) { throw new InvalidOperationException($"{nameof(Render)}: arranger dimensions for '{Arranger.Name}' are too small to render " + $"({Width}, {Height})"); } if (Width * Height != Image.Length) { Image = new byte[Width * Height]; } // TODO: Handle undefined elements explicitly and clear image subsections Array.Clear(Image, 0, Image.Length); var locations = Arranger.EnumerateElementLocationsWithinPixelRange(Left, Top, Width, Height); var imageRect = new Rectangle(Left, Top, Width, Height); foreach (var location in locations) { var el = Arranger.GetElement(location.X, location.Y); if (el is ArrangerElement element && element.Codec is IIndexedCodec codec) { var encodedBuffer = codec.ReadElement(element); // TODO: Detect reads past end of file more gracefully if (encodedBuffer.Length == 0) { continue; } var elementRect = new Rectangle(element.X1, element.Y1, element.Width, element.Height); elementRect.Intersect(imageRect); if (elementRect.IsEmpty) { continue; } int minX = Math.Clamp(element.X1, Left, Right - 1); int maxX = Math.Clamp(element.X2, Left, Right - 1); int minY = Math.Clamp(element.Y1, Top, Bottom - 1); int maxY = Math.Clamp(element.Y2, Top, Bottom - 1); int deltaX = minX - element.X1; int deltaY = minY - element.Y1; var decodedImage = codec.DecodeElement(element, encodedBuffer); decodedImage.RotateArray2D(element.Rotation); decodedImage.MirrorArray2D(element.Mirror); for (int y = 0; y <= maxY - minY; y++) { int destidx = (element.Y1 + deltaY + y - Top) * Width + (element.X1 + deltaX - Left); for (int x = 0; x <= maxX - minX; x++) { Image[destidx] = decodedImage[y + deltaY, x + deltaX]; destidx++; } } }