Render terrain from tilemap

This commit is contained in:
2026-05-09 00:32:32 +02:00
parent 1ca65eccf8
commit 70adeb010f
4 changed files with 49 additions and 90 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

View File

@@ -41,6 +41,7 @@
<canvas:CanvasControl <canvas:CanvasControl
x:Name="LevelCanvas" x:Name="LevelCanvas"
ClearColor="#101215" ClearColor="#101215"
CreateResources="LevelCanvas_CreateResources"
Draw="LevelCanvas_Draw" Draw="LevelCanvas_Draw"
PointerPressed="LevelCanvas_PointerPressed" PointerPressed="LevelCanvas_PointerPressed"
PointerMoved="LevelCanvas_PointerMoved" PointerMoved="LevelCanvas_PointerMoved"

View File

@@ -4,8 +4,8 @@ using Windows.Storage;
using Windows.Storage.Pickers; using Windows.Storage.Pickers;
using Windows.UI; using Windows.UI;
using Microsoft.Graphics.Canvas; using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Geometry;
using Microsoft.Graphics.Canvas.Text; using Microsoft.Graphics.Canvas.Text;
using Microsoft.Graphics.Canvas.UI;
using Microsoft.Graphics.Canvas.UI.Xaml; using Microsoft.Graphics.Canvas.UI.Xaml;
using Microsoft.UI; using Microsoft.UI;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
@@ -43,6 +43,16 @@ public sealed partial class MainWindow
RefreshInspector(); RefreshInspector();
} }
private void LevelCanvas_CreateResources(CanvasControl sender, CanvasCreateResourcesEventArgs args)
{
args.TrackAsyncAction(LoadTilemapAsync(sender).AsAsyncAction());
}
private async Task LoadTilemapAsync(CanvasControl sender)
{
m_TerrainTilemap = await CanvasBitmap.LoadAsync(sender, new Uri("ms-appx:///Images/tilemap.png"));
}
private void ToolPicker_SelectionChanged(object sender, SelectionChangedEventArgs e) private void ToolPicker_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
if (ToolPicker.SelectedItem is EEditorTool tool) if (ToolPicker.SelectedItem is EEditorTool tool)
@@ -213,99 +223,41 @@ public sealed partial class MainWindow
private void DrawDualTerrainTile(CanvasDrawingSession drawing, Rect rect, int floorMask) private void DrawDualTerrainTile(CanvasDrawingSession drawing, Rect rect, int floorMask)
{ {
var wallColor = ColorHelper.FromArgb(255, 54, 61, 68); if (m_TerrainTilemap is null)
var floorColor = ColorHelper.FromArgb(255, 31, 36, 40); return;
var wallMask = c_AllCorners ^ floorMask; var wallMask = c_AllCorners ^ floorMask;
var sourceRect = TilemapSourceRect(wallMask);
drawing.FillRectangle(rect, floorColor); drawing.DrawImage(m_TerrainTilemap, rect, sourceRect);
DrawDualTerrainTile(drawing, rect, wallColor, floorColor, GetDualTerrainTileId(wallMask));
} }
private static int GetDualTerrainTileId(int wallMask) private static Rect TilemapSourceRect(int wallMask)
{ {
return wallMask; var tilePosition = wallMask switch {
} c_BottomLeftCorner => new GridPosition(0, 0),
c_TopRightCorner | c_BottomRightCorner => new GridPosition(1, 0),
private static void DrawDualTerrainTile(CanvasDrawingSession drawing, Rect rect, Color wallColor, Color floorColor, int tileId) c_TopLeftCorner | c_BottomLeftCorner | c_BottomRightCorner => new GridPosition(2, 0),
{ c_BottomLeftCorner | c_BottomRightCorner => new GridPosition(3, 0),
if (tileId == 0) c_TopLeftCorner | c_BottomRightCorner => new GridPosition(0, 1),
return; c_BottomLeftCorner | c_TopRightCorner | c_BottomRightCorner => new GridPosition(1, 1),
c_AllCorners => new GridPosition(2, 1),
if (tileId == c_AllCorners) c_TopLeftCorner | c_BottomLeftCorner | c_TopRightCorner => new GridPosition(3, 1),
{ c_TopRightCorner => new GridPosition(0, 2),
drawing.FillRectangle(rect, wallColor); c_TopLeftCorner | c_TopRightCorner => new GridPosition(1, 2),
return; c_TopLeftCorner | c_TopRightCorner | c_BottomRightCorner => new GridPosition(2, 2),
} c_BottomLeftCorner | c_TopLeftCorner => new GridPosition(3, 2),
0 => new GridPosition(0, 3),
switch (tileId) c_BottomRightCorner => new GridPosition(1, 3),
{ c_BottomLeftCorner | c_TopRightCorner => new GridPosition(2, 3),
case c_TopLeftCorner: c_TopLeftCorner => new GridPosition(3, 3),
case c_TopRightCorner: _ => throw new ArgumentOutOfRangeException(nameof(wallMask), wallMask, "Unsupported tile mask.")
case c_BottomLeftCorner:
case c_BottomRightCorner:
DrawTerrainCorner(drawing, rect, wallColor, tileId);
break;
case c_TopLeftCorner | c_TopRightCorner:
drawing.FillRectangle(new(rect.X, rect.Y, rect.Width, rect.Height / 2), wallColor);
break;
case c_BottomLeftCorner | c_BottomRightCorner:
drawing.FillRectangle(new(rect.X, rect.Y + rect.Height / 2, rect.Width, rect.Height / 2), wallColor);
break;
case c_TopLeftCorner | c_BottomLeftCorner:
drawing.FillRectangle(new(rect.X, rect.Y, rect.Width / 2, rect.Height), wallColor);
break;
case c_TopRightCorner | c_BottomRightCorner:
drawing.FillRectangle(new(rect.X + rect.Width / 2, rect.Y, rect.Width / 2, rect.Height), wallColor);
break;
case c_TopLeftCorner | c_BottomRightCorner:
DrawTerrainCorner(drawing, rect, wallColor, c_TopLeftCorner);
DrawTerrainCorner(drawing, rect, wallColor, c_BottomRightCorner);
break;
case c_TopRightCorner | c_BottomLeftCorner:
DrawTerrainCorner(drawing, rect, wallColor, c_TopRightCorner);
DrawTerrainCorner(drawing, rect, wallColor, c_BottomLeftCorner);
break;
default:
drawing.FillRectangle(rect, wallColor);
DrawTerrainCorner(drawing, rect, floorColor, c_AllCorners ^ tileId);
break;
}
}
private static void DrawTerrainCorner(CanvasDrawingSession drawing, Rect rect, Color color, int corner)
{
var radiusX = (float)rect.Width / 2;
var radiusY = (float)rect.Height / 2;
var center = corner switch {
c_TopLeftCorner => new Vector2((float)rect.X, (float)rect.Y),
c_TopRightCorner => new Vector2((float)(rect.X + rect.Width), (float)rect.Y),
c_BottomRightCorner => new Vector2((float)(rect.X + rect.Width), (float)(rect.Y + rect.Height)),
c_BottomLeftCorner => new Vector2((float)rect.X, (float)(rect.Y + rect.Height)),
_ => new Vector2((float)(rect.X + rect.Width / 2), (float)(rect.Y + rect.Height / 2))
};
var start = corner switch {
c_TopLeftCorner => new Vector2(center.X + radiusX, center.Y),
c_TopRightCorner => new Vector2(center.X, center.Y + radiusY),
c_BottomRightCorner => new Vector2(center.X - radiusX, center.Y),
c_BottomLeftCorner => new Vector2(center.X, center.Y - radiusY),
_ => center
};
var end = corner switch {
c_TopLeftCorner => new Vector2(center.X, center.Y + radiusY),
c_TopRightCorner => new Vector2(center.X - radiusX, center.Y),
c_BottomRightCorner => new Vector2(center.X, center.Y - radiusY),
c_BottomLeftCorner => new Vector2(center.X + radiusX, center.Y),
_ => center
}; };
using var builder = new CanvasPathBuilder(drawing); return new(
builder.BeginFigure(center); tilePosition.X * c_TilemapTileSize,
builder.AddLine(start); tilePosition.Y * c_TilemapTileSize,
builder.AddArc(end, radiusX, radiusY, 0, CanvasSweepDirection.Clockwise, CanvasArcSize.Small); c_TilemapTileSize,
builder.EndFigure(CanvasFigureLoop.Closed); c_TilemapTileSize);
using var geometry = CanvasGeometry.CreatePath(builder);
drawing.FillGeometry(geometry, color);
} }
private int GetDualTileMask(int x, int y) private int GetDualTileMask(int x, int y)
@@ -486,11 +438,13 @@ public sealed partial class MainWindow
} }
private readonly SimulationEngine m_Simulation = new(); private readonly SimulationEngine m_Simulation = new();
private const int c_TilemapTileSize = 512;
private const int c_TopLeftCorner = 1; private const int c_TopLeftCorner = 1;
private const int c_TopRightCorner = 2; private const int c_TopRightCorner = 2;
private const int c_BottomLeftCorner = 4; private const int c_BottomLeftCorner = 4;
private const int c_BottomRightCorner = 8; private const int c_BottomRightCorner = 8;
private const int c_AllCorners = c_TopLeftCorner | c_TopRightCorner | c_BottomLeftCorner | c_BottomRightCorner; private const int c_AllCorners = c_TopLeftCorner | c_TopRightCorner | c_BottomLeftCorner | c_BottomRightCorner;
private CanvasBitmap? m_TerrainTilemap;
private StorageFile? m_CurrentFile; private StorageFile? m_CurrentFile;
private LevelState m_Level; private LevelState m_Level;
private bool m_Painting; private bool m_Painting;

View File

@@ -24,4 +24,8 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ReactorMaintenance.Simulation\ReactorMaintenance.Simulation.csproj" /> <ProjectReference Include="..\ReactorMaintenance.Simulation\ReactorMaintenance.Simulation.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Content Include="Images\tilemap.png" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project> </Project>