public byte[] SavePreview()
{
var tileset = Rules.TileSet;
var resources = Rules.Actors["world"].TraitInfos<ResourceTypeInfo>()
.ToDictionary(r => r.ResourceType, r => r.TerrainType);
using (var stream = new MemoryStream())
{
var isRectangularIsometric = Grid.Type == MapGridType.RectangularIsometric;
// Fudge the heightmap offset by adding as much extra as we need / can.
// This tries to correct for our incorrect assumption that MPos == PPos
var heightOffset = Math.Min(Grid.MaximumTerrainHeight, MapSize.Y - Bounds.Bottom);
var width = Bounds.Width;
var height = Bounds.Height + heightOffset;
var bitmapWidth = width;
if (isRectangularIsometric)
bitmapWidth = 2 * bitmapWidth - 1;
using (var bitmap = new Bitmap(bitmapWidth, height))
{
var bitmapData = bitmap.LockBits(bitmap.Bounds(),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
var colors = (int*)bitmapData.Scan0;
var stride = bitmapData.Stride / 4;
Color leftColor, rightColor;
for (var y = 0; y < height; y++)
{
for (var x = 0; x < width; x++)
{
var uv = new MPos(x + Bounds.Left, y + Bounds.Top);
var resourceType = Resources[uv].Type;
if (resourceType != 0)
{
// Cell contains resources
string res;
if (!resources.TryGetValue(resourceType, out res))
continue;
leftColor = rightColor = tileset[tileset.GetTerrainIndex(res)].Color;
}
else
{
// Cell contains terrain
var type = tileset.GetTileInfo(Tiles[uv]);
leftColor = type != null ? type.LeftColor : Color.Black;
rightColor = type != null ? type.RightColor : Color.Black;
}
if (isRectangularIsometric)
{
// Odd rows are shifted right by 1px
var dx = uv.V & 1;
if (x + dx > 0)
colors[y * stride + 2 * x + dx - 1] = leftColor.ToArgb();
if (2 * x + dx < stride)
colors[y * stride + 2 * x + dx] = rightColor.ToArgb();
}
else
colors[y * stride + x] = leftColor.ToArgb();
}
}
}
bitmap.UnlockBits(bitmapData);
bitmap.Save(stream, ImageFormat.Png);
}
return stream.ToArray();
}
}