From 1b9372ff7c7580612721b0f1220473f513247bbe Mon Sep 17 00:00:00 2001 From: Frank Tovar Date: Sun, 10 May 2026 23:04:48 +0200 Subject: [PATCH] Restore dual terrain tilemap rendering --- .../MainWindow.xaml.cs | 89 ++++++++++++++++++- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs b/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs index 4c68a01..2b8b416 100644 --- a/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs +++ b/src/ReactorMaintenance.Win2D/MainWindow.xaml.cs @@ -24,6 +24,11 @@ public sealed partial class MainWindow { return new(OriginX + (position.X * CellSize), OriginY + (position.Y * CellSize), CellSize, CellSize); } + + public Rect DualTileRect(int x, int y) + { + return new(OriginX + ((x - 0.5) * CellSize), OriginY + ((y - 0.5) * CellSize), CellSize, CellSize); + } } private sealed record ForecastViewModel(string Message); @@ -301,14 +306,84 @@ public sealed partial class MainWindow private void DrawTerrain(CanvasDrawingSession drawing, CanvasLayout layout) { - foreach (var position in AllPositions()) + for (var y = 0; y <= m_Level.Height; y++) { - var rect = layout.CellRect(position); - var color = m_Level.GetTerrain(position) == ECellTerrain.Wall ? ColorHelper.FromArgb(255, 41, 47, 52) : ColorHelper.FromArgb(255, 32, 38, 42); - drawing.FillRectangle(rect, color); + for (var x = 0; x <= m_Level.Width; x++) + DrawDualTerrainTile(drawing, layout.DualTileRect(x, y), GetDualTileMask(x, y)); } } + private void DrawDualTerrainTile(CanvasDrawingSession drawing, Rect rect, int floorMask) + { + if (m_TerrainTilemap is null) + { + DrawFallbackTerrainTile(drawing, rect, floorMask); + return; + } + + var wallMask = c_AllCorners ^ floorMask; + drawing.DrawImage(m_TerrainTilemap, rect, TilemapSourceRect(wallMask), 1.0f, CanvasImageInterpolation.HighQualityCubic); + } + + private static void DrawFallbackTerrainTile(CanvasDrawingSession drawing, Rect rect, int floorMask) + { + var color = floorMask == c_AllCorners ? ColorHelper.FromArgb(255, 32, 38, 42) : ColorHelper.FromArgb(255, 41, 47, 52); + drawing.FillRectangle(rect, color); + } + + private static Rect TilemapSourceRect(int wallMask) + { + var tilePosition = wallMask switch { + c_BottomLeftCorner => new GridPosition(0, 0), + c_TopRightCorner | c_BottomRightCorner => new(1, 0), + c_TopLeftCorner | c_BottomLeftCorner | c_BottomRightCorner => new(2, 0), + c_BottomLeftCorner | c_BottomRightCorner => new(3, 0), + c_TopLeftCorner | c_BottomRightCorner => new(0, 1), + c_BottomLeftCorner | c_TopRightCorner | c_BottomRightCorner => new(1, 1), + c_AllCorners => new(2, 1), + c_TopLeftCorner | c_BottomLeftCorner | c_TopRightCorner => new(3, 1), + c_TopRightCorner => new(0, 2), + c_TopLeftCorner | c_TopRightCorner => new(1, 2), + c_TopLeftCorner | c_TopRightCorner | c_BottomRightCorner => new(2, 2), + c_BottomLeftCorner | c_TopLeftCorner => new(3, 2), + 0 => new(0, 3), + c_BottomRightCorner => new(1, 3), + c_BottomLeftCorner | c_TopRightCorner => new(2, 3), + c_TopLeftCorner => new GridPosition(3, 3), + _ => throw new ArgumentOutOfRangeException(nameof(wallMask), wallMask, "Unsupported tile mask.") + }; + + return new( + tilePosition.X * c_TilemapTileSize, + tilePosition.Y * c_TilemapTileSize, + c_TilemapTileSize, + c_TilemapTileSize); + } + + private int GetDualTileMask(int x, int y) + { + var mask = 0; + if (GetTerrainOrWall(x - 1, y - 1) == ECellTerrain.Floor) + mask |= c_TopLeftCorner; + + if (GetTerrainOrWall(x, y - 1) == ECellTerrain.Floor) + mask |= c_TopRightCorner; + + if (GetTerrainOrWall(x - 1, y) == ECellTerrain.Floor) + mask |= c_BottomLeftCorner; + + if (GetTerrainOrWall(x, y) == ECellTerrain.Floor) + mask |= c_BottomRightCorner; + + return mask; + } + + private ECellTerrain GetTerrainOrWall(int x, int y) + { + var position = new GridPosition(x, y); + return m_Level.InBounds(position) ? m_Level.GetTerrain(position) : ECellTerrain.Wall; + } + private void DrawUnderground(CanvasDrawingSession drawing, CanvasLayout layout) { foreach (var position in AllPositions()) @@ -908,6 +983,12 @@ public sealed partial class MainWindow private const double c_MaxZoom = 4; private const double c_ZoomStep = 1.15; private const double c_ClickPixelThreshold = 10; + private const int c_TilemapTileSize = 512; + private const int c_TopLeftCorner = 1; + private const int c_TopRightCorner = 2; + private const int c_BottomLeftCorner = 4; + private const int c_BottomRightCorner = 8; + private const int c_AllCorners = c_TopLeftCorner | c_TopRightCorner | c_BottomLeftCorner | c_BottomRightCorner; private static readonly Color c_FuelColor = ColorHelper.FromArgb(255, 220, 170, 68); private static readonly Color c_CoolantColor = ColorHelper.FromArgb(255, 57, 174, 196); private static readonly Color c_ElectricityColor = ColorHelper.FromArgb(255, 236, 226, 82);