public void DrawTiles(Graphics g, Point p, Rectangle terrainRectangle, Func <Point, int> terrain) { // Calculate and clip screen coordinates of terrain var sx1 = Math.Max(p.X + terrainRectangle.Left * TileSize, (int)g.ClipBounds.Left); var sy1 = Math.Max(p.Y + terrainRectangle.Top * TileSize, (int)g.ClipBounds.Top); var sx2 = Math.Min(p.X + terrainRectangle.Right * TileSize, (int)g.ClipBounds.Right); var sy2 = Math.Min(p.Y + terrainRectangle.Bottom * TileSize, (int)g.ClipBounds.Bottom); if (sx1 >= sx2 || sy1 >= sy2) { return; } // Calculate clipped terrain coordinates var tx1 = (sx1 - p.X) / TileSize; var ty1 = (sy1 - p.Y) / TileSize; var tx2 = (sx2 - p.X) / TileSize; var ty2 = (sy2 - p.Y) / TileSize; // Prepare pixmap; pixmap covers screen coordinates (sx1,sy1) to (sx2,sy2) if (_Pixmap == null || _Pixmap.Width != sx2 - sx1 || _Pixmap.Height != sy2 - sy1) { _Pixmap = new Pixmap(sx2 - sx1, sy2 - sy1); } // Prepare layers pixmaps if (_PixmapsTileSize != TileSize) { foreach (var layer in _Layers) { layer.CreatePixmaps(TileSize); } _PixmapsTileSize = TileSize; } // Prepare terrain cache int originX = tx1 - 1; int originY = ty1 - 1; int sizeX = tx2 - tx1 + 2 + 2; int sizeY = ty2 - ty1 + 2 + 2; if (_Terrain == null || _Terrain.Length != sizeX * sizeY) { _Terrain = new int[sizeX * sizeY]; } for (int y = 0; y < sizeY; ++y) { for (int x = 0; x < sizeX; ++x) { _Terrain[x + y * sizeX] = terrain(new Point(x + originX, y + originY)); } } // Draw all layers foreach (var layer in _Layers) { if (layer.Layout == LayerLayout.Corners) { // For all terrain locations to draw Parallel.For(ty1, ty2 + 2, ty => // for (int ty = ty1; ty < ty2 + 2; ++ty) { for (int tx = tx1; tx < tx2 + 2; ++tx) { // Get pixmap position of terrain location int px = tx * TileSize + p.X - sx1 - TileSize / 2; int py = ty * TileSize + p.Y - sy1 - TileSize / 2; // Get layers masks of surrounding terrain locations (corners) int cmask1 = _Terrain[(tx - originX - 1) + (ty - originY - 1) * sizeX]; int cmask2 = _Terrain[(tx - originX) + (ty - originY - 1) * sizeX]; int cmask3 = _Terrain[(tx - originX - 1) + (ty - originY) * sizeX]; int cmask4 = _Terrain[(tx - originX) + (ty - originY) * sizeX]; // Prepare seed for selecting random variations of tiles int seed = tx | (ty << 16); // Draw tile int code = 0; if ((cmask1 & layer.ConnectionsMask) != 0) { code += 1; } if ((cmask2 & layer.ConnectionsMask) != 0) { code += 2; } if ((cmask3 & layer.ConnectionsMask) != 0) { code += 4; } if ((cmask4 & layer.ConnectionsMask) != 0) { code += 8; } if (code != 0) { Point coords = layer.GetTileCoords(code, seed); var srcRect = new Rectangle(TileSize * coords.X, TileSize * coords.Y, TileSize, TileSize); if (layer.WrapPixmap != null) { Pixmap.Draw2(layer.TilesPixmap, layer.WrapPixmap, _Pixmap, srcRect, new Point(tx * TileSize, ty * TileSize), new Point(px, py)); } else { Pixmap.Draw(layer.TilesPixmap, _Pixmap, srcRect, px, py); } } } }); } else { // For all terrain locations to draw Parallel.For(ty1, ty2 + 1, ty => //for (int ty = ty1; ty < ty2 + 1; ++ty) { for (int tx = tx1; tx < tx2 + 1; ++tx) { // If location contains this layer int mask = terrain(new Point(tx, ty)); if ((mask & layer.Mask) != 0) { // Get pixmap position of terrain location int px = tx * TileSize + p.X - sx1; int py = ty * TileSize + p.Y - sy1; // Get layers masks of surrounding terrain locations (sides) //int lmask = terrain(new Point(tx - 1, ty)); //int umask = terrain(new Point(tx, ty - 1)); //int rmask = terrain(new Point(tx + 1, ty)); //int dmask = terrain(new Point(tx, ty + 1)); int lmask = _Terrain[(tx - originX - 1) + (ty - originY) * sizeX]; int umask = _Terrain[(tx - originX) + (ty - originY - 1) * sizeX]; int rmask = _Terrain[(tx - originX + 1) + (ty - originY) * sizeX]; int dmask = _Terrain[(tx - originX) + (ty - originY + 1) * sizeX]; // Prepare seed for selecting random variations of tiles int seed = tx | (ty << 16); // Draw tile int code = 0; if ((lmask & layer.ConnectionsMask) != 0) { code += 1; } if ((umask & layer.ConnectionsMask) != 0) { code += 2; } if ((rmask & layer.ConnectionsMask) != 0) { code += 4; } if ((dmask & layer.ConnectionsMask) != 0) { code += 8; } Point coords = layer.GetTileCoords(code, seed); var srcRect = new Rectangle(TileSize * coords.X, TileSize * coords.Y, TileSize, TileSize); if (layer.WrapPixmap != null) { Pixmap.Draw2(layer.TilesPixmap, layer.WrapPixmap, _Pixmap, srcRect, new Point(tx * TileSize, ty * TileSize), new Point(px, py)); } else { Pixmap.Draw(layer.TilesPixmap, _Pixmap, srcRect, px, py); } } } }); } } // Copy pixmap to graphics g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed; g.DrawImageUnscaled(_Pixmap.Bitmap, new Point(sx1, sy1)); }