mirror of
https://github.com/kwsch/NHSE.git
synced 2026-04-07 17:35:00 -05:00
Closes #729 1. Dark mode now applied correctly (was previously lacking) 2. Fixed terrain brush action (brush active is higher priority than drag, fix tile fetch) 3. Fixed writing of Building/structure labels; apply after Terrain 4. Single terrain brush form allowed, center to Field Editor on launch Somewhat related: fix Show() load for non-ShowDialog() forms to center to parent.
146 lines
6.5 KiB
C#
146 lines
6.5 KiB
C#
using NHSE.Core;
|
|
using System;
|
|
using System.Drawing;
|
|
|
|
namespace NHSE.Sprites;
|
|
|
|
/// <summary>
|
|
/// Produces bitmaps for viewing map acres and full maps.
|
|
/// </summary>
|
|
public sealed class MapRenderer : IDisposable
|
|
{
|
|
/// <summary>
|
|
/// Data source for map rendering.
|
|
/// </summary>
|
|
private readonly MapEditor Map;
|
|
|
|
/// <summary> Scale factor for full map rendering. </summary>
|
|
private int MapScale => Map.MapScale;
|
|
|
|
/// <summary> Scale factor for acre viewport rendering. </summary>
|
|
private int ViewScale => Map.ViewScale;
|
|
|
|
// Cached acre view objects to remove allocation/GC
|
|
|
|
/// <summary> 1px scale viewport item layer pixel data. </summary>
|
|
private readonly int[] ViewportItems1;
|
|
/// <summary> Upscaled viewport item layer pixel data. </summary>
|
|
private readonly int[] ViewportItemsX;
|
|
/// <summary> Upscaled viewport item layer image. </summary>
|
|
private readonly Bitmap ViewportItemsImage;
|
|
|
|
/// <summary> Upscaled map item layer pixel data with reticle. </summary>
|
|
private readonly int[] MapItemsReticleX;
|
|
/// <summary> Upscaled map item layer image with reticle. </summary>
|
|
private readonly Bitmap MapItemsReticleImage;
|
|
|
|
/// <summary> 1px scale viewport terrain layer pixel data. </summary>
|
|
private readonly int[] ViewportTerrain1;
|
|
/// <summary> Upscaled viewport terrain layer pixel data. </summary>
|
|
private readonly int[] ViewportTerrainX;
|
|
/// <summary> Upscaled viewport terrain layer image. </summary>
|
|
private readonly Bitmap ViewportTerrainImage;
|
|
|
|
/// <summary> 1px scale map terrain layer pixel data. </summary>
|
|
private readonly int[] MapTerrain1;
|
|
/// <summary> Upscaled map terrain layer pixel data. </summary>
|
|
private readonly int[] MapTerrainX;
|
|
/// <summary> Upscaled map terrain layer image. </summary>
|
|
private readonly Bitmap MapTerrainImage;
|
|
|
|
public MapRenderer(MapEditor m)
|
|
{
|
|
Map = m;
|
|
|
|
// Initialize cached objects based on map size
|
|
// Get tile info from item layer, it's the tiniest cell we can render
|
|
var cfg = m.Mutator.Manager.ConfigItems;
|
|
var mapW = cfg.MapTotalWidth * MapScale;
|
|
var mapH = cfg.MapTotalHeight * MapScale;
|
|
MapItemsReticleImage = new Bitmap(mapW, mapH);
|
|
MapItemsReticleX = new int[mapW * mapH];
|
|
|
|
MapTerrain1 = new int[MapItemsReticleX.Length / (2 * 2)]; // 32px => 16px basis
|
|
MapTerrainX = new int[MapItemsReticleX.Length]; // 2x upscale
|
|
MapTerrainImage = new Bitmap(MapItemsReticleImage.Width, MapItemsReticleImage.Height);
|
|
MapTerrain1.AsSpan().Fill(TerrainSprite.ColorOcean); // blue color for ocean
|
|
|
|
// Render a single acre viewport
|
|
var tpa = cfg.TilesPerAcre;
|
|
ViewportItems1 = new int[tpa * tpa];
|
|
ViewportItemsX = new int[ViewportItems1.Length * ViewScale * ViewScale];
|
|
ViewportItemsImage = new Bitmap(tpa * ViewScale, tpa * ViewScale);
|
|
|
|
const byte pixelsPerTerrainTile = 16;
|
|
var dimTerrain = cfg.TilesPerAcre * pixelsPerTerrainTile;
|
|
ViewportTerrain1 = new int[dimTerrain * dimTerrain]; // each terrain tile is drawn as 16px, then we upscale
|
|
ViewportTerrainX = new int[ViewportItemsX.Length]; // 2x upscale (16px -> 32px)
|
|
ViewportTerrainImage = new Bitmap(ViewportItemsImage.Width, ViewportItemsImage.Height);
|
|
ViewportTerrain1.AsSpan().Fill(TerrainSprite.ColorOcean); // blue color for ocean
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
MapItemsReticleImage.Dispose();
|
|
MapTerrainImage.Dispose();
|
|
|
|
ViewportItemsImage.Dispose();
|
|
ViewportTerrainImage.Dispose();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the map items reticle bitmap for the current layer and view position.
|
|
/// </summary>
|
|
/// <param name="transparency">Transparency of items (not including reticle).</param>
|
|
/// <param name="drawReticle">Option to draw the reticle.</param>
|
|
/// <returns>Updated bitmap with reticle.</returns>
|
|
public Bitmap UpdateMapItemsReticle(int transparency, bool drawReticle = true)
|
|
=> UpdateMapItemsReticle(Map.Mutator.CurrentLayer, Map.Mutator.View.X, Map.Mutator.View.Y, transparency, drawReticle);
|
|
|
|
/// <summary>
|
|
/// Updates the map terrain bitmap.
|
|
/// </summary>
|
|
/// <param name="selectedBuildingIndex">Index of building to highlight, or -1 for none.</param>
|
|
/// <returns>Updated map terrain bitmap.</returns>
|
|
public Bitmap UpdateMapTerrain(int selectedBuildingIndex = -1)
|
|
=> TerrainSprite.GetMapWithBuildings(MapTerrainImage, Map, MapTerrain1, MapTerrainX, selectedBuildingIndex);
|
|
|
|
/// <summary>
|
|
/// Updates the viewport items bitmap for the current layer and view position.
|
|
/// </summary>
|
|
/// <param name="transparency">Transparency of items.</param>
|
|
public Bitmap UpdateViewportItems(int transparency)
|
|
=> UpdateViewportItems(Map.Mutator.View.X, Map.Mutator.View.Y, transparency);
|
|
|
|
/// <summary>
|
|
/// Updates the viewport terrain bitmap.
|
|
/// </summary>
|
|
/// <param name="textFont">Font to use for building labels.</param>
|
|
/// <param name="transparencyBuilding">Transparency for building shapes drawn on terrain.</param>
|
|
/// <param name="transparencyTerrain">Transparency for terrain layer.</param>
|
|
/// <param name="selectedBuildingIndex">Index of building to highlight, or -1 for none.</param>
|
|
/// <returns></returns>
|
|
public Bitmap UpdateViewportTerrain(Font textFont, byte transparencyBuilding, byte transparencyTerrain, int selectedBuildingIndex = -1)
|
|
{
|
|
TerrainSprite.LoadViewport(ViewportTerrainImage, Map, textFont, ViewportTerrain1, ViewportTerrainX, selectedBuildingIndex, transparencyBuilding, transparencyTerrain);
|
|
return ViewportTerrainImage;
|
|
}
|
|
|
|
private Bitmap UpdateMapItemsReticle(LayerFieldItem layer, int absX, int absY, int transparency, bool drawReticle = true)
|
|
{
|
|
var cfg = Map.Mutator.Manager.ConfigItems;
|
|
ItemLayerSprite.LoadItemLayer1(cfg, layer, MapItemsReticleX, transparency);
|
|
MapItemsReticleImage.SetBitmapData(MapItemsReticleX);
|
|
if (drawReticle)
|
|
ItemLayerSprite.DrawViewReticle(MapItemsReticleImage, layer.TileInfo, absX, absY);
|
|
return MapItemsReticleImage;
|
|
}
|
|
|
|
private Bitmap UpdateViewportItems(int absX, int absY, int transparency)
|
|
{
|
|
var cfg = Map.Mutator.Manager.ConfigItems;
|
|
var layer = Map.Mutator.CurrentLayer;
|
|
ItemLayerSprite.LoadViewport(ViewportItemsImage, layer, cfg, absX, absY, ViewportItems1, ViewportItemsX, ViewScale, transparency);
|
|
return ViewportItemsImage;
|
|
}
|
|
} |