From 45a057ef7aa261e2396cefd61588f4bc409928d6 Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Sun, 23 Jun 2024 06:38:05 -0400 Subject: [PATCH 1/2] Implement screen edge anchors --- OpenDreamShared/Dream/ScreenLocation.cs | 57 ++++++++++++++++++------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/OpenDreamShared/Dream/ScreenLocation.cs b/OpenDreamShared/Dream/ScreenLocation.cs index 27cef2ec09..bf0f34c57d 100644 --- a/OpenDreamShared/Dream/ScreenLocation.cs +++ b/OpenDreamShared/Dream/ScreenLocation.cs @@ -6,19 +6,24 @@ using System.Linq; using System.Text; using Robust.Shared.Log; +using Robust.Shared.Maths; namespace OpenDreamShared.Dream; public enum HorizontalAnchor { Left, Center, - Right + Right, + West, + East } public enum VerticalAnchor { Bottom, Center, - Top + Top, + South, + North } [Serializable, NetSerializable] @@ -66,20 +71,24 @@ public ScreenLocation(string screenLocation) { ParseScreenLoc(screenLocation); } - public Vector2 GetViewPosition(Vector2 viewOffset, ViewRange view, float iconSize) { - float x = (X + PixelOffsetX / iconSize); + public Vector2 GetViewPosition(Vector2 viewOffset, ViewRange view, float worldIconSize, Vector2 spriteIconSize, Vector2 controlSize) { + float x = (X + PixelOffsetX / worldIconSize); x += HorizontalAnchor switch { - HorizontalAnchor.Left => 0, - HorizontalAnchor.Center => view.CenterX, - HorizontalAnchor.Right => view.Width - 1, + HorizontalAnchor.Left => spriteIconSize.X - 1, + HorizontalAnchor.West => 0, + HorizontalAnchor.Center => controlSize.X / 2, + HorizontalAnchor.East => view.Width - 1, + HorizontalAnchor.Right => controlSize.X - spriteIconSize.X, _ => throw new Exception($"Invalid horizontal anchor {HorizontalAnchor}") }; - float y = (Y + PixelOffsetY / iconSize); + float y = (Y + PixelOffsetY / worldIconSize); y += VerticalAnchor switch { - VerticalAnchor.Bottom => 0, - VerticalAnchor.Center => view.CenterY, - VerticalAnchor.Top => view.Height - 1, + VerticalAnchor.Bottom => spriteIconSize.Y - 1, + VerticalAnchor.South => 0, + VerticalAnchor.Center => controlSize.Y / 2, + VerticalAnchor.North => view.Height - 1, + VerticalAnchor.Top => controlSize.Y - spriteIconSize.Y, _ => throw new Exception($"Invalid vertical anchor {VerticalAnchor}") }; @@ -121,10 +130,14 @@ private void ParseScreenLoc(string screenLoc) { (HorizontalAnchor, VerticalAnchor) = coordinateSplit[0].Trim() switch { "CENTER" => (HorizontalAnchor.Center, VerticalAnchor.Center), - "NORTHWEST" or "TOPLEFT" => (HorizontalAnchor.Left, VerticalAnchor.Top), - "NORTHEAST" or "TOPRIGHT" => (HorizontalAnchor.Right, VerticalAnchor.Top), - "SOUTHWEST" or "BOTTOMLEFT" => (HorizontalAnchor.Left, VerticalAnchor.Bottom), - "SOUTHEAST" or "BOTTOMRIGHT" => (HorizontalAnchor.Right, VerticalAnchor.Bottom), + "NORTHWEST" => (HorizontalAnchor.West, VerticalAnchor.North), + "TOPLEFT" => (HorizontalAnchor.Left, VerticalAnchor.Top), + "NORTHEAST" => (HorizontalAnchor.East, VerticalAnchor.North), + "TOPRIGHT" => (HorizontalAnchor.Right, VerticalAnchor.Top), + "SOUTHWEST" => (HorizontalAnchor.West, VerticalAnchor.South), + "BOTTOMLEFT" => (HorizontalAnchor.Left, VerticalAnchor.Bottom), + "SOUTHEAST" => (HorizontalAnchor.East, VerticalAnchor.South), + "BOTTOMRIGHT" => (HorizontalAnchor.Right, VerticalAnchor.Bottom), _ => throw new Exception($"Invalid screen_loc {screenLoc}") }; @@ -193,23 +206,35 @@ private bool ParseScreenLocCoordinate(string coordinate, bool isHorizontal) { break; case "WEST": - case "LEFT": // Yes, this sets the horizontal anchor regardless of the isHorizontal arg. // Every macro sets their respective axis regardless of which coordinate it's in + HorizontalAnchor = HorizontalAnchor.West; + settingHorizontal = true; + break; + case "LEFT": HorizontalAnchor = HorizontalAnchor.Left; settingHorizontal = true; break; case "EAST": + HorizontalAnchor = HorizontalAnchor.East; + settingHorizontal = true; + break; case "RIGHT": HorizontalAnchor = HorizontalAnchor.Right; settingHorizontal = true; break; case "NORTH": + VerticalAnchor = VerticalAnchor.North; + settingHorizontal = false; + break; case "TOP": VerticalAnchor = VerticalAnchor.Top; settingHorizontal = false; break; case "SOUTH": + VerticalAnchor = VerticalAnchor.South; + settingHorizontal = false; + break; case "BOTTOM": VerticalAnchor = VerticalAnchor.Bottom; settingHorizontal = false; From f06f5d207be0d8dfc0af0229420c72951a369a8b Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Sun, 23 Jun 2024 06:38:45 -0400 Subject: [PATCH 2/2] Adjust screen object origin --- OpenDreamClient/Rendering/DreamViewOverlay.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/OpenDreamClient/Rendering/DreamViewOverlay.cs b/OpenDreamClient/Rendering/DreamViewOverlay.cs index 55eb129c44..5b1cb8d543 100644 --- a/OpenDreamClient/Rendering/DreamViewOverlay.cs +++ b/OpenDreamClient/Rendering/DreamViewOverlay.cs @@ -672,8 +672,16 @@ private void CollectVisibleSprites(ViewAlgorithm.Tile?[,] tiles, EntityUid gridU if (sprite.ScreenLocation.MapControl != null) // Don't render screen objects meant for other map controls continue; - Vector2 position = sprite.ScreenLocation.GetViewPosition(worldAABB.BottomLeft, _interfaceManager.View, EyeManager.PixelsPerMeter); Vector2 iconSize = sprite.Icon.DMI == null ? Vector2.Zero : sprite.Icon.DMI.IconSize / (float)EyeManager.PixelsPerMeter; + Interface.Descriptors.ControlDescriptorMap mapDescriptor = (Interface.Descriptors.ControlDescriptorMap) _interfaceManager.DefaultMap.ElementDescriptor; + var viewport = _interfaceManager.DefaultMap.Viewport; + float mapZoom = mapDescriptor.IconSize.Value != 0 ? EyeManager.PixelsPerMeter / (float) mapDescriptor.IconSize.Value : 1; + // Limit the viewport drawbox just to what's visible on-screen. + var drawBox = viewport.GetDrawBox().Intersection(_interfaceManager.DefaultMap.Viewport.GlobalPixelRect.Intersection(_interfaceManager.DefaultMap.UIElement.GlobalPixelRect) ?? UIBox2i.FromDimensions(0, 0, 0, 0)) ?? UIBox2i.FromDimensions(0, 0, 0, 0); + Vector2 viewportTileSize = Vector2.Min(drawBox.Size, viewport.Size) * mapZoom / (float)EyeManager.PixelsPerMeter; + // WorldAABB.BottomLeft is offscreen, so instead we use drawBox to get the onscreen component. + MapCoordinates viewOffset = viewport.ScreenToMap(drawBox.BottomLeft); + Vector2 position = sprite.ScreenLocation.GetViewPosition(viewOffset.Position, _interfaceManager.View, EyeManager.PixelsPerMeter, iconSize, viewportTileSize); for (int x = 0; x < sprite.ScreenLocation.RepeatX; x++) { for (int y = 0; y < sprite.ScreenLocation.RepeatY; y++) { tValue = 0;