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();
		
		// number of tiles in x direction 
		int tpx = (int) Math.floor(viewportBounds.getX() / info.getTileSize(0));
		// number of tiles in y direction 
		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);
					}
				}
			}
		}
	}