Crossfire JXClient, Trunk  R20561
AbstractGUIMap.java
Go to the documentation of this file.
1 /*
2  * This file is part of JXClient, the Fullscreen Java Crossfire Client.
3  *
4  * JXClient is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * JXClient is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with JXClient; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  * Copyright (C) 2005-2008 Yann Chachkoff.
19  * Copyright (C) 2006-2011 Andreas Kirschbaum.
20  */
21 
22 package com.realtime.crossfire.jxclient.gui.map;
23 
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;
52 import java.util.Map;
53 import java.util.Set;
54 import javax.swing.ImageIcon;
55 import org.jetbrains.annotations.NotNull;
56 import org.jetbrains.annotations.Nullable;
57 
63 public abstract class AbstractGUIMap extends AbstractGUIElement {
64 
68  private static final long serialVersionUID = 1;
69 
74  private final boolean avoidCopyArea;
75 
79  @NotNull
81 
85  @NotNull
87 
92  @Nullable
94 
99  @NotNull
101 
106  @NotNull
107  private final Object bufferedImageSync = new Object();
108 
113  @Nullable
114  private transient BufferedImage bufferedImage;
115 
119  private boolean clearMapPending = true;
120 
124  @NotNull
125  private final Deque<Long> scrollMapPending = new ArrayDeque<>();
126 
130  private int mapWidth;
131 
135  private int mapHeight;
136 
140  private final int tileSize;
141 
145  private int playerX;
146 
150  private int playerY;
151 
155  private int offsetX;
156 
160  private int offsetY;
161 
166  private int displayMinX;
167 
172  private int displayMaxX;
173 
178  private int displayMinY;
179 
184  private int displayMaxY;
185 
190  private int displayMinOffsetX;
191 
196  @SuppressWarnings("JavaDoc")
197  private int displayMaxOffsetX;
198 
203  private int displayMinOffsetY;
204 
209  @SuppressWarnings("JavaDoc")
210  private int displayMaxOffsetY;
211 
216  @NotNull
217  private final Map<Color, Image> images = new HashMap<>();
218 
222  @NotNull
223  private final MapListener mapListener = new MapListener() {
224 
225  @Override
226  public void mapChanged(@NotNull final CfMap map, @NotNull final Set<CfMapSquare> changedSquares) {
227  assert Thread.holdsLock(map);
228  synchronized (bufferedImageSync) {
229  final int x0 = map.getOffsetX();
230  final int y0 = map.getOffsetY();
231  final Graphics2D g = createBufferGraphics(map);
232  try {
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) {
238  redrawSquare(g, mapSquare, map, x, y);
239  }
240  }
241  }
242  markPlayer(g, 0, 0);
243  } finally {
244  g.dispose();
245  }
246  }
247  setChanged();
248  }
249 
250  };
251 
255  @NotNull
256  private final NewmapListener newmapListener = () -> {
257  synchronized (bufferedImageSync) {
258  clearMapPending = true;
259  scrollMapPending.clear();
260  }
261  setChanged();
262  };
263 
268  private void clearMap(@NotNull final Graphics2D g) {
269  g.setColor(Color.BLACK);
270  g.fillRect(0, 0, getWidth(), getHeight());
271  g.setColor(DarknessColors.FOG_OF_WAR_COLOR);
272  g.fillRect(0, 0, getWidth(), getHeight());
273  }
274 
278  @NotNull
279  private final MapScrollListener mapscrollListener = (dx, dy) -> {
280  synchronized (bufferedImageSync) {
281  scrollMapPending.offerLast(((long)dx<<32)|(dy&0xFFFFFFFFL));
282  }
283  setChanged();
284  };
285 
289  @NotNull
290  private final MapSizeListener mapSizeListener = (mapWidth1, mapHeight1) -> {
291  setMapSize(mapWidth1, mapHeight1);
292  redrawAll();
293  };
294 
309  protected 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) {
310  super(tooltipManager, elementListener, name, Transparency.TRANSLUCENT);
311  this.avoidCopyArea = avoidCopyArea;
312  this.smoothingRenderer = smoothingRenderer;
313  this.darknessColors = darknessColors;
314  tileSize = facesProvider.getSize();
315  assert tileSize > 0;
316  this.mapUpdaterState = mapUpdaterState;
317  this.facesProvider = facesProvider;
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());
323  }
324 
328  @Override
329  public void dispose() {
330  super.dispose();
331  mapUpdaterState.removeMapSizeListener(mapSizeListener);
332  mapUpdaterState.removeCrossfireNewmapListener(newmapListener);
333  mapUpdaterState.removeCrossfireMapScrollListener(mapscrollListener);
334  mapUpdaterState.removeCrossfireMapListener(mapListener);
335  }
336 
340  private void redrawAll() {
341  final CfMap map = mapUpdaterState.getMap();
342  //noinspection SynchronizationOnLocalVariableOrMethodParameter
343  synchronized (map) {
344  //noinspection NestedSynchronizedStatement
345  synchronized (bufferedImageSync) {
346  final Graphics g = createBufferGraphics(map);
347  try {
348  redrawTiles(g, map, displayMinX, displayMinY, displayMaxX, displayMaxY);
349  markPlayer(g, 0, 0);
350  } finally {
351  g.dispose();
352  }
353  }
354  }
355  }
356 
362  private void redrawAllUnlessDirty(@NotNull final Graphics g, @NotNull final CfMap map) {
363  redrawTilesUnlessDirty(g, map, displayMinX-offsetX/tileSize, displayMinY-offsetY/tileSize, displayMaxX-offsetX/tileSize, displayMaxY-offsetY/tileSize);
364  }
365 
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);
382  }
383  }
384  }
385 
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++) {
398  redrawSquareUnlessDirty(g, map, x, y);
399  }
400  }
401  }
402 
412  private void redrawSquareUnlessDirty(@NotNull final Graphics g, @NotNull final CfMap map, final int x, final int y) {
413  final CfMapSquare mapSquare = map.getMapSquareUnlessDirty(x, y);
414  if (mapSquare != null) {
415  redrawSquare(g, mapSquare, map, x, y);
416  }
417  }
418 
427  protected void redrawSquare(@NotNull final Graphics g, @NotNull final CfMapSquare mapSquare, @NotNull final CfMap map, final int x, final int y) {
428  redrawSquare(g, x, y, mapSquare, map);
429  if (x < 0 || y < 0 || x >= mapWidth || y >= mapHeight || mapSquare.isFogOfWar()) {
430  paintColoredSquare(g, DarknessColors.FOG_OF_WAR_COLOR, offsetX+x*tileSize, offsetY+y*tileSize);
431  }
432  final int darkness = mapSquare.getDarkness();
433  if (darkness < CfMapSquare.DARKNESS_FULL_BRIGHT) {
434  paintColoredSquare(g, darknessColors.getDarknessColor(darkness), offsetX+x*tileSize, offsetY+y*tileSize);
435  }
436  }
437 
446  private void redrawSquare(@NotNull final Graphics g, final int x, final int y, @NotNull final CfMapSquare mapSquare, @NotNull final CfMap map) {
447  final int px = offsetX+x*tileSize;
448  final int py = offsetY+y*tileSize;
449  final int mapSquareX = mapSquare.getX();
450  final int mapSquareY = mapSquare.getY();
451  boolean foundSquare = false;
452  for (int layer = 0; layer < Map2.NUM_LAYERS; layer++) {
453  final CfMapSquare headMapSquare = mapSquare.getHeadMapSquare(layer);
454  if (headMapSquare != null) {
455  final Face headFace = headMapSquare.getFace(layer);
456  assert headFace != null; // getHeadMapSquare() would have been cleared in this case
457  final int dx = headMapSquare.getX()-mapSquareX;
458  final int dy = headMapSquare.getY()-mapSquareY;
459  assert dx > 0 || dy > 0;
460  if (!foundSquare) {
461  foundSquare = true;
462  paintSquareBackground(g, px, py, true, mapSquare);
463  }
464  paintImage(g, headFace, px, py, tileSize*dx, tileSize*dy);
465  }
466 
467  final Face face = mapSquare.getFace(layer);
468  if (face != null) {
469  if (!foundSquare) {
470  foundSquare = true;
471  paintSquareBackground(g, px, py, true, mapSquare);
472  }
473  paintImage(g, face, px, py, 0, 0);
474  if (smoothingRenderer != null) {
475  smoothingRenderer.paintSmooth(g, x, y, px, py, layer, map, tileSize);
476  }
477  }
478  }
479  if (!foundSquare) {
480  paintSquareBackground(g, px, py, false, mapSquare);
481  }
482  }
483 
492  protected abstract void paintSquareBackground(@NotNull final Graphics g, final int px, final int py, final boolean hasImage, @NotNull final CfMapSquare mapSquare);
493 
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;
507  g.drawImage(imageIcon.getImage(), px, py, px+tileSize, py+tileSize, sx-tileSize, sy-tileSize, sx, sy, null);
508  }
509 
516  protected abstract void markPlayer(@NotNull final Graphics g, final int dx, final int dy);
517 
521  @Override
522  public void paintComponent(@NotNull final Graphics g) {
523  super.paintComponent(g);
524  synchronized (bufferedImageSync) {
525  g.drawImage(bufferedImage, 0, 0, null);
526  }
527  }
528 
534  private void setMapSize(final int mapWidth, final int mapHeight) {
535  this.mapWidth = mapWidth;
536  this.mapHeight = mapHeight;
537 
538  final int nX = MathUtils.divRoundUp(playerX, tileSize);
539  displayMinOffsetX = playerX-nX*tileSize;
540  assert -tileSize < displayMinOffsetX && displayMinOffsetX <= 0;
541  assert (playerX-displayMinOffsetX)%tileSize == 0;
542  displayMinX = (mapWidth-1)/2-nX;
543  final int tilesX = MathUtils.divRoundUp(getWidth()-displayMinOffsetX, tileSize);
544  displayMaxX = displayMinX+tilesX;
545  assert (displayMaxX-displayMinX)*tileSize >= getWidth();
546  assert (displayMaxX-displayMinX)*tileSize-getWidth() < 2*tileSize;
547  displayMaxOffsetX = MathUtils.mod(-displayMinOffsetX-getWidth(), tileSize);
548  offsetX = displayMinOffsetX-displayMinX*tileSize;
549 
550  final int nY = MathUtils.divRoundUp(playerY, tileSize);
551  displayMinOffsetY = playerY-nY*tileSize;
552  assert -tileSize < displayMinOffsetY && displayMinOffsetY <= 0;
553  assert (playerY-displayMinOffsetY)%tileSize == 0;
554  displayMinY = (mapHeight-1)/2-nY;
555  final int tilesY = MathUtils.divRoundUp(getHeight()-displayMinOffsetY, tileSize);
556  displayMaxY = displayMinY+tilesY;
557  assert (displayMaxY-displayMinY)*tileSize >= getHeight();
558  assert (displayMaxY-displayMinY)*tileSize-getHeight() < 2*tileSize;
559  displayMaxOffsetY = MathUtils.mod(-displayMinOffsetY-getHeight(), tileSize);
560  offsetY = displayMinOffsetY-displayMinY*tileSize;
561 
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);
566  redrawAll();
567  }
568 
573  public int getPlayerX() {
574  return playerX;
575  }
576 
581  public int getPlayerY() {
582  return playerY;
583  }
584 
589  public int getOffsetX() {
590  return offsetX;
591  }
592 
597  public int getOffsetY() {
598  return offsetY;
599  }
600 
604  @Override
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;
609  setMapSize(mapWidth, mapHeight);
610  redrawAll();
611  }
612 
620  private void updateScrolledMap(@NotNull final Graphics g, @NotNull final CfMap map, final int dx, final int dy) {
621  if (avoidCopyArea || Math.abs(dx)*tileSize >= getWidth() || Math.abs(dy)*tileSize >= getHeight()) {
622  redrawAllUnlessDirty(g, map);
623  } else {
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);
629 
630  if (dx > 0) {
631  final int ww = (displayMaxOffsetX == 0 ? 0 : 1)+dx;
632  redrawTilesUnlessDirty(g, map, displayMaxX-ww, displayMinY, displayMaxX, displayMaxY);
633  } else if (dx < 0) {
634  final int ww = (displayMinOffsetX == 0 ? 0 : 1)-dx;
635  redrawTilesUnlessDirty(g, map, displayMinX, displayMinY, displayMinX+ww, displayMaxY);
636  }
637  if (dy > 0) {
638  final int hh = (displayMaxOffsetY == 0 ? 0 : 1)+dy;
639  redrawTilesUnlessDirty(g, map, displayMinX, displayMaxY-hh, displayMaxX, displayMaxY);
640  } else if (dy < 0) {
641  final int hh = (displayMinOffsetY == 0 ? 0 : 1)-dy;
642  redrawTilesUnlessDirty(g, map, displayMinX, displayMinY, displayMaxX, displayMinY+hh);
643  }
644  }
645  }
646 
654  protected void paintColoredSquare(@NotNull final Graphics g, @NotNull final Color color, final int x, final int y) {
655  Image image = images.get(color);
656  if (image == null) {
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();
659  try {
660  g2.setColor(color);
661  g2.fillRect(0, 0, tileSize, tileSize);
662  } finally {
663  g2.dispose();
664  }
665  image = tmp;
666  images.put(color, image);
667  }
668  g.drawImage(image, x, y, tileSize, tileSize, null);
669  }
670 
675  protected int getMapWidth() {
676  return mapWidth;
677  }
678 
683  protected int getMapHeight() {
684  return mapHeight;
685  }
686 
694  @NotNull
695  private Graphics2D createBufferGraphics(@NotNull final CfMap map) {
696  assert Thread.holdsLock(bufferedImageSync);
697  assert bufferedImage != null;
698  final Graphics2D graphics = bufferedImage.createGraphics();
699  if (clearMapPending) {
700  clearMapPending = false;
701  clearMap(graphics);
702  }
703  while (true) {
704  final Long scrollMap = scrollMapPending.pollFirst();
705  if (scrollMap == null) {
706  break;
707  }
708  final long tmp = scrollMap;
709  final int dx = (int)(tmp>>32);
710  final int dy = (int)tmp;
711  updateScrolledMap(graphics, map, dx, dy);
712  markPlayer(graphics, dx, dy);
713  }
714  return graphics;
715  }
716 
720  @Nullable
721  @Override
722  public Dimension getMinimumSize() {
723  return new Dimension(tileSize, tileSize);
724  }
725 
726 }
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.
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).
Definition: CfMap.java:45
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.
Definition: MathUtils.java:55
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.
Interface for listeners interested on map scrolled events.
Implements the map model which is shown in the map and magic map views.
Definition: CfMap.java:22
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 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.
Definition: Map2.java:33
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.
Utility class for mathematical functions.
Definition: MathUtils.java:28
Interface defining an abstract GUI element.
Definition: GUIElement.java:32
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.
final FacesProvider facesProvider
The FacesProvider for looking up faces.
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.
Definition: Map2.java:28
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.
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.
Definition: MathUtils.java:66
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.
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.