22 package com.realtime.crossfire.jxclient.gui.map;
39 import java.awt.Color;
40 import java.awt.Dimension;
41 import java.awt.Graphics;
42 import java.awt.Graphics2D;
43 import java.awt.GraphicsConfiguration;
44 import java.awt.GraphicsDevice;
45 import java.awt.GraphicsEnvironment;
46 import java.awt.Image;
47 import java.awt.Transparency;
48 import java.awt.image.BufferedImage;
49 import java.util.ArrayDeque;
50 import java.util.Deque;
51 import java.util.HashMap;
54 import javax.swing.ImageIcon;
55 import org.jetbrains.annotations.NotNull;
56 import org.jetbrains.annotations.Nullable;
196 @SuppressWarnings(
"JavaDoc")
209 @SuppressWarnings("JavaDoc")
217 private final Map<Color, Image>
images = new HashMap<>();
226 public void mapChanged(@NotNull
final CfMap map, @NotNull
final Set<CfMapSquare> changedSquares) {
227 assert Thread.holdsLock(map);
229 final int x0 = map.getOffsetX();
230 final int y0 = map.getOffsetY();
233 for (
final CfMapSquare mapSquare : changedSquares) {
234 final int x = mapSquare.getX()+x0;
235 if (displayMinX <= x && x < displayMaxX) {
236 final int y = mapSquare.getY()+y0;
237 if (displayMinY <= y && y < displayMaxY) {
258 clearMapPending =
true;
259 scrollMapPending.clear();
268 private void clearMap(@NotNull
final Graphics2D g) {
269 g.setColor(Color.BLACK);
270 g.fillRect(0, 0, getWidth(), getHeight());
272 g.fillRect(0, 0, getWidth(), getHeight());
281 scrollMapPending.offerLast(((
long)dx<<32)|(dy&0xFFFFFFFFL));
310 super(tooltipManager, elementListener, name, Transparency.TRANSLUCENT);
314 tileSize = facesProvider.getSize();
318 this.mapUpdaterState.addMapSizeListener(mapSizeListener);
319 this.mapUpdaterState.addCrossfireMapListener(
mapListener);
320 this.mapUpdaterState.addCrossfireNewmapListener(newmapListener);
321 this.mapUpdaterState.addCrossfireMapScrollListener(mapscrollListener);
322 setMapSize(this.mapUpdaterState.getMapWidth(), this.mapUpdaterState.getMapHeight());
348 redrawTiles(g, map, displayMinX, displayMinY, displayMaxX, displayMaxY);
363 redrawTilesUnlessDirty(g, map, displayMinX-offsetX/tileSize, displayMinY-offsetY/tileSize, displayMaxX-offsetX/tileSize, displayMaxY-offsetY/tileSize);
375 private void redrawTiles(@NotNull
final Graphics g, @NotNull
final CfMap map,
final int x0,
final int y0,
final int x1,
final int y1) {
376 for (
int x = x0; x < x1; x++) {
377 for (
int y = y0; y < y1; y++) {
378 final int mapSquareX = x-offsetX/
tileSize;
379 final int mapSquareY = y-offsetY/
tileSize;
380 final CfMapSquare mapSquare = map.getMapSquare(mapSquareX, mapSquareY);
381 redrawSquare(g, mapSquare, map, mapSquareX, mapSquareY);
395 private void redrawTilesUnlessDirty(@NotNull
final Graphics g, @NotNull
final CfMap map,
final int x0,
final int y0,
final int x1,
final int y1) {
396 for (
int x = x0; x < x1; x++) {
397 for (
int y = y0; y < y1; y++) {
413 final CfMapSquare mapSquare = map.getMapSquareUnlessDirty(x, y);
414 if (mapSquare != null) {
429 if (x < 0 || y < 0 || x >= mapWidth || y >= mapHeight || mapSquare.isFogOfWar()) {
432 final int darkness = mapSquare.getDarkness();
449 final int mapSquareX = mapSquare.getX();
450 final int mapSquareY = mapSquare.getY();
451 boolean foundSquare =
false;
454 if (headMapSquare != null) {
455 final Face headFace = headMapSquare.
getFace(layer);
456 assert headFace != null;
457 final int dx = headMapSquare.
getX()-mapSquareX;
458 final int dy = headMapSquare.
getY()-mapSquareY;
459 assert dx > 0 || dy > 0;
464 paintImage(g, headFace, px, py, tileSize*dx, tileSize*dy);
467 final Face face = mapSquare.getFace(layer);
474 if (smoothingRenderer != null) {
475 smoothingRenderer.
paintSmooth(g, x, y, px, py, layer, map, tileSize);
492 protected abstract void paintSquareBackground(@NotNull
final Graphics g,
final int px,
final int py,
final boolean hasImage, @NotNull
final CfMapSquare mapSquare);
503 private void paintImage(@NotNull
final Graphics g, @NotNull
final Face face,
final int px,
final int py,
final int offsetX,
final int offsetY) {
504 final ImageIcon imageIcon = facesProvider.
getImageIcon(face.getFaceNum(), null);
505 final int sx = imageIcon.getIconWidth()-
offsetX;
506 final int sy = imageIcon.getIconHeight()-
offsetY;
516 protected abstract void markPlayer(@NotNull
final Graphics g,
final int dx,
final int dy);
523 super.paintComponent(g);
525 g.drawImage(bufferedImage, 0, 0, null);
534 private void setMapSize(
final int mapWidth,
final int mapHeight) {
539 displayMinOffsetX = playerX-nX*
tileSize;
540 assert -tileSize < displayMinOffsetX && displayMinOffsetX <= 0;
541 assert (playerX-displayMinOffsetX)%tileSize == 0;
542 displayMinX = (mapWidth-1)/2-nX;
544 displayMaxX = displayMinX+tilesX;
545 assert (displayMaxX-displayMinX)*tileSize >= getWidth();
546 assert (displayMaxX-displayMinX)*tileSize-getWidth() < 2*
tileSize;
548 offsetX = displayMinOffsetX-displayMinX*
tileSize;
553 assert (playerY-displayMinOffsetY)%tileSize == 0;
554 displayMinY = (mapHeight-1)/2-nY;
556 displayMaxY = displayMinY+tilesY;
557 assert (displayMaxY-displayMinY)*tileSize >= getHeight();
558 assert (displayMaxY-displayMinY)*tileSize-getHeight() < 2*
tileSize;
560 offsetY = displayMinOffsetY-displayMinY*
tileSize;
562 final GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
563 final GraphicsDevice graphicsDevice = graphicsEnvironment.getDefaultScreenDevice();
564 final GraphicsConfiguration graphicsConfiguration = graphicsDevice.getDefaultConfiguration();
565 bufferedImage = graphicsConfiguration.createCompatibleImage(Math.max(1, getWidth()), Math.max(1, getHeight()), Transparency.TRANSLUCENT);
605 public void setBounds(
final int x,
final int y,
final int width,
final int height) {
606 super.setBounds(x, y, width, height);
607 playerX = width/2-tileSize/2;
608 playerY = height/2-tileSize/2;
621 if (avoidCopyArea || Math.abs(dx)*tileSize >= getWidth() || Math.abs(dy)*tileSize >= getHeight()) {
624 final int x = dx > 0 ? dx : 0;
625 final int w = dx > 0 ? -dx : dx;
626 final int y = dy > 0 ? dy : 0;
627 final int h = dy > 0 ? -dy : dy;
628 g.copyArea(x*tileSize, y*tileSize, getWidth()+w*tileSize, getHeight()+h*tileSize, -dx*tileSize, -dy*tileSize);
634 final int ww = (displayMinOffsetX == 0 ? 0 : 1)-dx;
654 protected void paintColoredSquare(@NotNull
final Graphics g, @NotNull
final Color color,
final int x,
final int y) {
655 Image image =
images.get(color);
657 final BufferedImage tmp =
new BufferedImage(tileSize, tileSize, color.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB);
658 final Graphics g2 = tmp.createGraphics();
661 g2.fillRect(0, 0, tileSize, tileSize);
668 g.drawImage(image, x, y, tileSize, tileSize, null);
696 assert Thread.holdsLock(bufferedImageSync);
697 assert bufferedImage != null;
698 final Graphics2D graphics = bufferedImage.createGraphics();
699 if (clearMapPending) {
700 clearMapPending =
false;
704 final Long scrollMap = scrollMapPending.pollFirst();
705 if (scrollMap == null) {
708 final long tmp = scrollMap;
709 final int dx = (int)(tmp>>32);
710 final int dy = (int)tmp;
723 return new Dimension(tileSize, tileSize);
Listener for GUIElement related events.
final SmoothingRenderer smoothingRenderer
The SmoothingRenderer to use or.
void removeMapSizeListener(@NotNull final MapSizeListener listener)
Removes a listener to be notified about map size changes.
static final long serialVersionUID
The serial version UID.
int mapHeight
The map height in squares.
CfMapSquare getHeadMapSquare(final int layer)
Returns the map square of the head of a multi-square object.
void redrawTiles(@NotNull final Graphics g, @NotNull final CfMap map, final int x0, final int y0, final int x1, final int y1)
Redraws a rectangular area of tiles.
Color getDarknessColor(final int darkness)
Returns an overlay color for a darkness value.
final TooltipManager tooltipManager
The TooltipManager to update.
Represents a square in a CfMap.
final boolean avoidCopyArea
Whether map scrolling is done by copying pixel areas.
CfMap getMap()
Returns the current map instance.
abstract void markPlayer(@NotNull final Graphics g, final int dx, final int dy)
Paints the player location.
Represents a map (as seen by the client).
int getOffsetY()
Returns the y offset for drawing the square at coordinate 0 of the map.
ImageIcon getImageIcon(int faceNum, @Nullable boolean[] isUnknownImage)
Returns the face for a face ID.
void setChanged()
Records that the contents have changed and must be repainted.
static int mod(final int numerator, final int denominator)
Calculates the remainder of.
int getX()
Returns the absolute map x-coordinate of this square.
int getMapHeight()
Returns the map height in squares.
void paintImage(@NotNull final Graphics g, @NotNull final Face face, final int px, final int py, final int offsetX, final int offsetY)
Paints a face into a tile.
void removeCrossfireNewmapListener(@NotNull final NewmapListener listener)
Removes a listener to notify about cleared maps.
int displayMinOffsetX
The distance the leftmost visible tile reaches outside the map window.
final Map< Color, Image > images
Maps Color to an image filled with this color with a size of one square.
Implements the map model which is shown in the map and magic map views.
int displayMinX
The tile x coordinate where map drawing starts.
int displayMaxOffsetY
The number of pixels that are visible in the bottommost visible tile.
void paintComponent(@NotNull final Graphics g)
void removeCrossfireMapScrollListener(@NotNull final MapScrollListener listener)
Removes a listener to notify about scrolled maps.
int displayMaxX
The tile x coordinate where map drawing ends.
abstract void paintSquareBackground(@NotNull final Graphics g, final int px, final int py, final boolean hasImage, @NotNull final CfMapSquare mapSquare)
Paints the background of a map square.
Manages image information ("faces") needed to display the map view, items, and spell icons...
transient BufferedImage bufferedImage
An BufferedImage having the size of this component.
Abstract base class for GUIElements that display map views.
final GUIElementListener elementListener
The GUIElementListener to notify.
void paintSmooth(@NotNull final Graphics graphics, final int x, final int y, final int px, final int py, final int layer, @NotNull final CfMap map, final int tileSize)
Draw the smoothing information at given position of map, for a given limit smoothlevel, at a given layer.
int getY()
Returns the absolute map y-coordinate of this square.
int NUM_LAYERS
The total number of map layers to display.
void redrawSquare(@NotNull final Graphics g, @NotNull final CfMapSquare mapSquare, @NotNull final CfMap map, final int x, final int y)
Redraws one square.
int playerY
The y offset of the tile representing the player.
final String name
The name of this element.
Utility class for mathematical functions.
Interface defining an abstract GUI element.
void redrawSquare(@NotNull final Graphics g, final int x, final int y, @NotNull final CfMapSquare mapSquare, @NotNull final CfMap map)
Redraws one layer of a square.
final MapListener mapListener
The MapListener registered to receive map updates.
Listener for clients interested in map size changes.
int getPlayerY()
Returns the y offset of the tile representing the player.
final NewmapListener newmapListener
The NewmapListener registered to receive newmap commands.
boolean clearMapPending
Whether the map area should be blanked.
int getMapWidth()
Returns the map width in squares.
int mapWidth
The map width in squares.
final FacesProvider facesProvider
The FacesProvider for looking up faces.
Interface for face providers.
int getOffsetX()
Returns the x offset for drawing the square at coordinate 0 of the map.
void setBounds(final int x, final int y, final int width, final int height)
Interface defining constants for the "map2" Crossfire protocol message.
Interface for listeners interested in changes within CfMap instances.
void dispose()
Releases all allocated resources.
AbstractGUIMap(final boolean avoidCopyArea, @NotNull final TooltipManager tooltipManager, @NotNull final GUIElementListener elementListener, @NotNull final String name, @NotNull final MapUpdaterState mapUpdaterState, @NotNull final FacesProvider facesProvider, @Nullable final SmoothingRenderer smoothingRenderer, @NotNull final DarknessColors darknessColors)
Creates a new instance.
final MapScrollListener mapscrollListener
The MapScrollListener registered to receive map_scroll commands.
Dimension getMinimumSize()
void redrawAllUnlessDirty(@NotNull final Graphics g, @NotNull final CfMap map)
Redraws all non-dirty tiles.
void updateScrolledMap(@NotNull final Graphics g, @NotNull final CfMap map, final int dx, final int dy)
Updates the map display after the map contents have scrolled.
int getPlayerX()
Returns the x offset of the tile representing the player.
Update a CfMap model from protocol commands.
void setMapSize(final int mapWidth, final int mapHeight)
Sets the map size.
int offsetX
The x offset for drawing the square at coordinate 0 of the map.
void redrawSquareUnlessDirty(@NotNull final Graphics g, @NotNull final CfMap map, final int x, final int y)
Redraws one square if it is not dirty.
final MapUpdaterState mapUpdaterState
The MapUpdaterState instance to display.
final MapSizeListener mapSizeListener
The MapSizeListener registered to detect map size changes.
final DarknessColors darknessColors
The DarknessColors instance for converting darkness values into colors.
Graphics2D createBufferGraphics(@NotNull final CfMap map)
Returns a Graphics instance for painting into bufferedImage.
int displayMinY
The tile y coordinate where map drawing starts.
static int divRoundUp(final int numerator, final int denominator)
Returns the quotient of two values, rounded up to the nearest integer.
void paintColoredSquare(@NotNull final Graphics g, @NotNull final Color color, final int x, final int y)
Fills a square with one Color.
static final Color FOG_OF_WAR_COLOR
The color to use for overlaying fog-of-war tiles.
Renderer for painting smoothed faces into map views.
Face getFace(final int layer)
Returns the face of a layer.
Utility class for converting darkness values into colors.
int playerX
The x offset of the tile representing the player.
Abstract base class for GUI elements to be shown in Guis.
int offsetY
The y offset for drawing the square at coordinate 0 of the map.
Interface for listeners interested in received "newmap" messages.
int displayMinOffsetY
The distance the topmost visible tile reaches outside the map window.
final Object bufferedImageSync
Synchronizes access to bufferedImage, clearMapPending, and scrollMapPending.
int displayMaxY
The tile y coordinate where map drawing ends.
void removeCrossfireMapListener(@NotNull final MapListener listener)
Removes a listener to notify about changed map squares.
final int tileSize
The size of one tile.
int displayMaxOffsetX
The number of pixels that are visible in the rightmost visible tile.
final Deque< Long > scrollMapPending
Pending map scrolls.
static final int DARKNESS_FULL_BRIGHT
The darkness value for a full bright square.
void redrawAll()
Redraws the complete map view.
void redrawTilesUnlessDirty(@NotNull final Graphics g, @NotNull final CfMap map, final int x0, final int y0, final int x1, final int y1)
Redraws a rectangular area of non-dirty tiles.
void clearMap(@NotNull final Graphics2D g)
Blanks the map display.