protected void drawMapTiles(final Graphics g, final int zoom, Rectangle viewportBounds) {
        int size = getTileFactory().getTileSize(zoom);
        Dimension mapSize = getTileFactory().getMapSize(zoom);

        // calculate the "visible" viewport area in tiles
        int numWide = viewportBounds.width / size + 2;
        int numHigh = viewportBounds.height / size + 2;

        // TilePoint topLeftTile = getTileFactory().getTileCoordinate(
        // new Point2D.Double(viewportBounds.x, viewportBounds.y));
        TileFactoryInfo info = getTileFactory().getInfo();
        int tpx = (int) Math.floor(viewportBounds.getX() / info.getTileSize(0));
        int tpy = (int) Math.floor(viewportBounds.getY() / info.getTileSize(0));
        // TilePoint topLeftTile = new TilePoint(tpx, tpy);

        // p("top tile = " + topLeftTile);
        // fetch the tiles from the factory and store them in the tiles cache
        // attach the tileLoadListener
        for (int x = 0; x <= numWide; x++) {
            for (int y = 0; y <= numHigh; y++) {
                int itpx = x + tpx;// topLeftTile.getX();
                int itpy = y + tpy;// topLeftTile.getY();
                // TilePoint point = new TilePoint(x + topLeftTile.getX(), y + topLeftTile.getY());
                // only proceed if the specified tile point lies within the area being painted
                if (g.getClipBounds().intersects(
                        new Rectangle(itpx * size - viewportBounds.x, itpy * size - viewportBounds.y, size, size))) {
                    Tile tile = getTileFactory().getTile(itpx, itpy, zoom);
                    int ox = ((itpx * getTileFactory().getTileSize(zoom)) - viewportBounds.x);
                    int oy = ((itpy * getTileFactory().getTileSize(zoom)) - viewportBounds.y);

                    // if the tile is off the map to the north/south, then just don't paint anything
                    if (isTileOnMap(itpx, itpy, mapSize)) {
                        if (isOpaque()) {
                            g.setColor(getBackground());
                            g.fillRect(ox, oy, size, size);
                        }
                    } else if (tile.isLoaded()) {
                        g.drawImage(tile.getImage(), ox, oy, null);
                    } else {
                        // Use tile at higher zoom level with 200% magnification
                        Tile superTile = getTileFactory().getTile(itpx / 2, itpy / 2, zoom + 1);

                        if (superTile.isLoaded()) {
                            int offX = (itpx % 2) * size / 2;
                            int offY = (itpy % 2) * size / 2;
                            g.drawImage(superTile.getImage(), ox, oy, ox + size, oy + size, offX, offY, offX + size / 2, offY + size / 2, null);
                        } else {
                            int imageX = (getTileFactory().getTileSize(zoom) - getLoadingImage().getWidth(null)) / 2;
                            int imageY = (getTileFactory().getTileSize(zoom) - getLoadingImage().getHeight(null)) / 2;
                            g.setColor(Color.GRAY);
                            g.fillRect(ox, oy, size, size);
                            g.drawImage(getLoadingImage(), ox + imageX, oy + imageY, null);
                        }
                    }
                    if (isDrawTileBorders()) {

                        g.setColor(Color.black);
                        g.drawRect(ox, oy, size, size);
                        g.drawRect(ox + size / 2 - 5, oy + size / 2 - 5, 10, 10);
                        g.setColor(Color.white);
                        g.drawRect(ox + 1, oy + 1, size, size);

                        String text = itpx + ", " + itpy + ", " + getZoom();
                        g.setColor(Color.BLACK);
                        g.drawString(text, ox + 10, oy + 30);
                        g.drawString(text, ox + 10 + 2, oy + 30 + 2);
                        g.setColor(Color.WHITE);
                        g.drawString(text, ox + 10 + 1, oy + 30 + 1);
                    }
                }
            }
        }
    }