mirror of
https://github.com/kwsch/NHSE.git
synced 2026-04-24 23:27:14 -05:00
nearly there
map renders, viewport renders still need to render buildings and terrain labels correctly, but it's NEARLY THERE
This commit is contained in:
parent
0a80175810
commit
49067d2a2b
|
|
@ -140,31 +140,79 @@ public void SetAllRoad(TerrainTile tile, bool interiorOnly = true)
|
|||
}
|
||||
}
|
||||
|
||||
public int GetTileColor(int x, int y, int insideX, int insideY)
|
||||
/// <inheritdoc cref="GetTileColor(ushort,int,int,int,int)"/>
|
||||
public int GetTileColor(int relX, int relY, int insideX, int insideY)
|
||||
{
|
||||
var acre = GetAcreTemplate(x, y);
|
||||
return GetTileColor(acre, x, y, insideX, insideY);
|
||||
var acre = GetAcreTemplate(relX, relY);
|
||||
return GetTileColor(acre, relX, relY, insideX, insideY);
|
||||
}
|
||||
|
||||
public int GetTileColor(ushort acre, int x, int y, int insideX, int insideY)
|
||||
/// <summary>
|
||||
/// Gets the base acre tile color at the specified terrain coordinates.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the acre has a predefined appearance, that is used; otherwise, the terrain-based appearance is used.
|
||||
/// </remarks>
|
||||
/// <param name="acre">Base acre underneath the terrain tile.</param>
|
||||
/// <param name="relX">Relative X coordinate in terrain tiles.</param>
|
||||
/// <param name="relY">Relative Y coordinate in terrain tiles.</param>
|
||||
/// <param name="insideX">Inside X coordinate of the terrain tile (16px max).</param>
|
||||
/// <param name="insideY">Inside Y coordinate of the terrain tile (16px max).</param>
|
||||
/// <returns>ARGB color value.</returns>
|
||||
public int GetTileColor(ushort acre, int relX, int relY, int insideX, int insideY)
|
||||
{
|
||||
if (acre != 0) // predefined appearance
|
||||
{
|
||||
var c = AcreTileColor.GetAcreTileColor(acre, x % 16, y % 16);
|
||||
var c = AcreTileColor.GetAcreTileColor(acre, relX % 16, relY % 16);
|
||||
if (c != -0x1000000) // transparent
|
||||
return c;
|
||||
}
|
||||
|
||||
// dynamic (terrain-based) appearance
|
||||
var tile = GetTile(x, y);
|
||||
var tile = GetTile(relX, relY);
|
||||
return TerrainTileColor.GetTileColor(tile, insideX, insideY).ToArgb();
|
||||
}
|
||||
|
||||
public ushort GetAcreTemplate(int terrainX, int terrainY)
|
||||
|
||||
/// <summary>
|
||||
/// Gets the base acre tile color at the specified terrain coordinates.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the acre has a predefined appearance, that is used; otherwise, the terrain-based appearance is used.
|
||||
/// </remarks>
|
||||
/// <param name="acre">Base acre underneath the terrain tile.</param>
|
||||
/// <param name="tile">Terrain tile to render.</param>
|
||||
/// <param name="relX">Relative X coordinate in terrain tiles.</param>
|
||||
/// <param name="relY">Relative Y coordinate in terrain tiles.</param>
|
||||
/// <param name="insideX">Inside X coordinate of the terrain tile (16px max).</param>
|
||||
/// <param name="insideY">Inside Y coordinate of the terrain tile (16px max).</param>
|
||||
/// <returns>ARGB color value.</returns>
|
||||
public int GetTileColor(ushort acre, TerrainTile tile, int relX, int relY, int insideX, int insideY)
|
||||
{
|
||||
// If acre is entirely transparent (interior acre), dynamic (terrain-based) appearance
|
||||
if (acre == 0)
|
||||
return TerrainTileColor.GetTileColor(tile, insideX, insideY).ToArgb();
|
||||
|
||||
// For beaches, a slim edge is customizable (indicative by a transparent value).
|
||||
// Check if pre-defined appearance governs
|
||||
var color = AcreTileColor.GetAcreTileColor(acre, relX % 16, relY % 16);
|
||||
if (color == -0x1000000) // transparent (dynamic)
|
||||
return TerrainTileColor.GetTileColor(tile, insideX, insideY).ToArgb();
|
||||
|
||||
return color; // pre-defined appearance
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the base acre template at the specified terrain coordinates.
|
||||
/// </summary>
|
||||
/// <param name="relX">Relative X coordinate in terrain tiles.</param>
|
||||
/// <param name="relY">Relative Y coordinate in terrain tiles.</param>
|
||||
/// <returns>Base acre underneath the terrain tile.</returns>
|
||||
public ushort GetAcreTemplate(int relX, int relY)
|
||||
{
|
||||
// Acres are 16x16 tiles, and the acre data has a 1-acre deep-sea border around it.
|
||||
var acreX = 1 + (terrainX / 16);
|
||||
var acreY = 1 + (terrainY / 16);
|
||||
var acreX = 1 + (relX / 16);
|
||||
var acreY = 1 + (relY / 16);
|
||||
|
||||
var acreIndex = ((CountAcreWidth + 2) * acreY) + acreX;
|
||||
var ofs = acreIndex * 2;
|
||||
|
|
|
|||
|
|
@ -60,9 +60,10 @@ public MapRenderer(MapEditor m)
|
|||
MapItemsReticleImage = new Bitmap(mapW, mapH);
|
||||
MapItemsReticleX = new int[mapW * mapH];
|
||||
|
||||
MapTerrain1 = new int[MapItemsReticleX.Length / (MapScale * MapScale)];
|
||||
MapTerrainX = new int[MapItemsReticleX.Length];
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ public static class TerrainSprite
|
|||
private static readonly Color PlazaColor = Color.RosyBrown;
|
||||
private static readonly StringFormat BuildingTextFormat = new() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
|
||||
|
||||
public const int ColorOcean = unchecked((int)0xFF80D7C3);
|
||||
private const int ColorGrid1 = unchecked((int)0xFF888888u); // lighter
|
||||
private const int ColorGrid2 = unchecked((int)0xFF666666u); // darker
|
||||
|
||||
// 6x5 in a 16x16 acre scale. Since we are in 32x32 scale for items, our upscale is "double".
|
||||
// Tiles are always rendered as 16x16 squares, to match the precomputed tile appearance bitmaps.
|
||||
private const int TileScale = 16;
|
||||
|
|
@ -28,34 +32,26 @@ public static class TerrainSprite
|
|||
private const int PlazaWidth = 6 * Scale;
|
||||
private const int PlazaHeight = 5 * Scale;
|
||||
|
||||
public static void GenerateMap(Bitmap map, MapMutator mut, Span<int> scale1, Span<int> scaleX, int imgScale, int acreIndex = -1)
|
||||
public static void GenerateMap(Bitmap map, MapMutator mut, Span<int> scale1, Span<int> scaleX, int imgScale)
|
||||
{
|
||||
// Load the terrain pixels, then upscale.
|
||||
var mgr = mut.Manager.LayerTerrain;
|
||||
LoadTerrainPixels(mgr, scale1);
|
||||
LoadTerrainPixels(mgr, mut.Manager.ConfigTerrain, scale1);
|
||||
ImageUtil.ScalePixelImage(scale1, scaleX, map.Width, map.Height, imgScale);
|
||||
map.SetBitmapData(scaleX);
|
||||
|
||||
if (acreIndex < 0)
|
||||
return;
|
||||
|
||||
var acre = AcreCoordinate.Acres[acreIndex];
|
||||
var x = acre.X * mgr.TileInfo.ViewWidth;
|
||||
var y = acre.Y * mgr.TileInfo.ViewHeight;
|
||||
|
||||
DrawReticle(map, mgr.TileInfo, x, y, imgScale);
|
||||
}
|
||||
|
||||
public static Bitmap GetMapWithBuildings(Bitmap map, MapEditor m, Font? f,
|
||||
Span<int> scale1, Span<int> scaleX,
|
||||
int buildingIndex = -1)
|
||||
{
|
||||
GenerateMap(map, m.Mutator, scale1, scaleX, m.MapScale);
|
||||
var imgScale = m.MapScale * 2; // because terrain is 16px per tile, items are 32px per tile
|
||||
GenerateMap(map, m.Mutator, scale1, scaleX, imgScale);
|
||||
using var gfx = Graphics.FromImage(map);
|
||||
|
||||
var plaza = m.Mutator.Manager.Plaza;
|
||||
gfx.DrawPlaza(m, (ushort)plaza.X, (ushort)plaza.Z, m.MapScale);
|
||||
gfx.DrawBuildings(m, m.Buildings.Buildings, m.MapScale, f, buildingIndex);
|
||||
gfx.DrawPlaza(m, (ushort)plaza.X, (ushort)plaza.Z, imgScale);
|
||||
gfx.DrawBuildings(m.Buildings.Buildings, imgScale, f, buildingIndex);
|
||||
return map;
|
||||
}
|
||||
|
||||
|
|
@ -81,10 +77,8 @@ public static void GenerateMap(Bitmap map, MapMutator mut, Span<int> scale1, Spa
|
|||
img.GetBitmapData(scaleX);
|
||||
|
||||
// Apply Grid
|
||||
const int grid1 = unchecked((int)0xFF888888u); // lighter
|
||||
const int grid2 = unchecked((int)0xFF666666u); // darker
|
||||
ItemLayerSprite.DrawGrid(scaleX, img.Width, img.Height, grid1, m.ViewScale); // minor
|
||||
ItemLayerSprite.DrawGrid(scaleX, img.Width, img.Height, grid2, m.ViewScale * 2); // major
|
||||
ItemLayerSprite.DrawGrid(scaleX, img.Width, img.Height, ColorGrid1, m.ViewScale); // minor
|
||||
ItemLayerSprite.DrawGrid(scaleX, img.Width, img.Height, ColorGrid2, m.ViewScale * 2); // major
|
||||
|
||||
// Switch back to graphics mode
|
||||
img.SetBitmapData(scaleX);
|
||||
|
|
@ -124,44 +118,46 @@ private static void DrawViewBuildings(this Graphics gfx, MapEditor m, int select
|
|||
var orig = ((SolidBrush)pen).Color;
|
||||
pen = new SolidBrush(Color.FromArgb(transBuild, orig));
|
||||
}
|
||||
gfx.DrawBuilding(b, m, pen, m.ViewScale, Text);
|
||||
gfx.DrawBuilding(b, pen, m.ViewScale, Text);
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadTerrainPixels(LayerTerrain mgr, Span<int> pixels)
|
||||
private static void LoadTerrainPixels(LayerTerrain mgr, LayerPositionConfig cfg, Span<int> pixels)
|
||||
{
|
||||
var (shiftX, shiftY) = cfg.GetCoordinatesAbsolute(0, 0);
|
||||
|
||||
// Iterate through the relative positions within the layer.
|
||||
// Then, map to absolute positions in the bitmap with the configured shift.
|
||||
var width = cfg.LayerTotalWidth;
|
||||
var height = cfg.LayerTotalHeight;
|
||||
var mapWidth = cfg.MapTotalWidth; // 1px scale
|
||||
|
||||
// Populate the image, with each pixel being a single tile.
|
||||
var width = mgr.TileInfo.TotalWidth;
|
||||
var height = mgr.TileInfo.TotalHeight;
|
||||
var i = 0;
|
||||
// Only need to render the layer's width/height, as the rest is ocean/unable to be changed.
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++, i++)
|
||||
pixels[i] = mgr.GetTileColor(x, y, x, y);
|
||||
var absY = y + shiftY;
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
var absX = x + shiftX;
|
||||
var color = mgr.GetTileColor(x, y, 0, 0);
|
||||
var offset = (absY * mapWidth) + absX;
|
||||
pixels[offset] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawReticle(Bitmap map, TileGridViewport mgr, int x, int y, int scale)
|
||||
private static void DrawPlaza(this Graphics gfx, MapEditor map, ushort px, ushort py, int imgScale)
|
||||
{
|
||||
using var gfx = Graphics.FromImage(map);
|
||||
using var pen = new Pen(Color.Red);
|
||||
var (x, y) = (px * imgScale, py * imgScale);
|
||||
|
||||
int w = mgr.ViewWidth * scale;
|
||||
int h = mgr.ViewHeight * scale;
|
||||
gfx.DrawRectangle(pen, x * scale, y * scale, w, h);
|
||||
}
|
||||
|
||||
private static void DrawPlaza(this Graphics gfx, MapEditor map, ushort px, ushort py, int scale)
|
||||
{
|
||||
var (x, y) = map.GetViewCoordinatesBuilding(px, py);
|
||||
|
||||
int width = scale * PlazaWidth;
|
||||
int height = scale * PlazaHeight;
|
||||
int width = imgScale * PlazaWidth;
|
||||
int height = imgScale * PlazaHeight;
|
||||
|
||||
gfx.FillRectangle(Plaza, x, y, width, height);
|
||||
}
|
||||
|
||||
private static void DrawBuildings(this Graphics gfx, MapEditor map, IReadOnlyList<Building> buildings, int imgScale, Font? textFont = null, int selectedBuildingIndex = -1)
|
||||
private static void DrawBuildings(this Graphics gfx, IReadOnlyList<Building> buildings, int imgScale, Font? textFont = null, int selectedBuildingIndex = -1)
|
||||
{
|
||||
for (int i = 0; i < buildings.Count; i++)
|
||||
{
|
||||
|
|
@ -170,13 +166,14 @@ private static void DrawBuildings(this Graphics gfx, MapEditor map, IReadOnlyLis
|
|||
continue;
|
||||
|
||||
var pen = selectedBuildingIndex == i ? Selected : Others;
|
||||
gfx.DrawBuilding(b, map, pen, imgScale, Text, textFont);
|
||||
gfx.DrawBuilding(b, pen, imgScale, Text, textFont);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawBuilding(this Graphics gfx, Building b, MapEditor map, Brush bBrush, int imgScale, Brush textBrush, Font? textFont = null)
|
||||
private static void DrawBuilding(this Graphics gfx, Building b, Brush bBrush,
|
||||
int imgScale, Brush textBrush, Font? textFont = null)
|
||||
{
|
||||
var (x, y) = map.GetViewCoordinatesBuilding(b.X, b.Y);
|
||||
var (x, y) = (b.X * imgScale, b.Y * imgScale);
|
||||
var type = b.BuildingType;
|
||||
var (width, height) = type.GetDimensions();
|
||||
|
||||
|
|
@ -197,12 +194,11 @@ private static void DrawBuilding(this Graphics gfx, Building b, MapEditor map, B
|
|||
private static void SetViewTerrainPixels(LayerTerrain t, LayerPositionConfig cfg, int relX, int relY, Span<int> data, Span<int> scaleX, int imgScale)
|
||||
{
|
||||
GetViewTerrain1(t, cfg, relX, relY, data);
|
||||
ImageUtil.ScalePixelImage(data, scaleX, TilesPerViewport * imgScale, TilesPerViewport * imgScale, imgScale);
|
||||
ImageUtil.ScalePixelImage(data, scaleX, TilesPerViewport * TileScale * imgScale, TilesPerViewport * TileScale * imgScale, imgScale);
|
||||
}
|
||||
|
||||
private static void GetViewTerrain1(LayerTerrain t, LayerPositionConfig cfg, int relX, int relY, Span<int> data)
|
||||
{
|
||||
int index = 0;
|
||||
for (int tileY = 0; tileY < TilesPerViewport; tileY++)
|
||||
{
|
||||
var actY = tileY + relY;
|
||||
|
|
@ -210,15 +206,31 @@ private static void GetViewTerrain1(LayerTerrain t, LayerPositionConfig cfg, int
|
|||
{
|
||||
var actX = relX + x;
|
||||
if (!cfg.IsCoordinateValidRelative(actX, actY))
|
||||
continue;
|
||||
|
||||
var acreTemplate = t.GetAcreTemplate(actX, actY);
|
||||
for (int pixelY = 0; pixelY < TileScale; pixelY++)
|
||||
{
|
||||
for (int pixelX = 0; pixelX < TileScale; pixelX++)
|
||||
// Fill tile's square with a solid color.
|
||||
for (int pixelY = 0; pixelY < TileScale; pixelY++)
|
||||
{
|
||||
data[index] = t.GetTileColor(acreTemplate, actX, actY, pixelX, pixelY);
|
||||
index++;
|
||||
var index = (tileY * TileScale + pixelY) * (TilesPerViewport * TileScale) + x * TileScale;
|
||||
for (int pixelX = 0; pixelX < TileScale; pixelX++)
|
||||
{
|
||||
data[index] = ColorOcean;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fill tile's square from terrain data.
|
||||
var acreTemplate = t.GetAcreTemplate(actX, actY);
|
||||
var tile = t.GetTile(actX, actY);
|
||||
for (int pixelY = 0; pixelY < TileScale; pixelY++)
|
||||
{
|
||||
var index = (tileY * TileScale + pixelY) * (TilesPerViewport * TileScale) + x * TileScale;
|
||||
for (int pixelX = 0; pixelX < TileScale; pixelX++)
|
||||
{
|
||||
data[index] = t.GetTileColor(acreTemplate, tile, actX, actY, pixelX, pixelY);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user