Gridarta Editor
FlatMapRenderer.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2015 The Gridarta Developers.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 package net.sf.gridarta.var.crossfire.gui.map.renderer;
21 
22 import java.awt.Color;
23 import java.awt.Dimension;
24 import java.awt.Graphics;
25 import java.awt.Image;
26 import java.awt.Point;
27 import java.awt.Rectangle;
28 import java.awt.image.BufferedImage;
29 import java.awt.image.RenderedImage;
30 import java.lang.ref.SoftReference;
31 import javax.swing.Icon;
32 import javax.swing.ImageIcon;
49 import org.apache.log4j.Category;
50 import org.apache.log4j.Logger;
51 import org.jetbrains.annotations.NotNull;
52 import org.jetbrains.annotations.Nullable;
53 
59 
63  @NotNull
64  private static final Category LOG = Logger.getLogger(FlatMapRenderer.class);
65 
69  private static final long serialVersionUID = 1L;
70 
75  @NotNull
77 
81  @NotNull
83 
88  @NotNull
89  private final Color[] highLightMask = { new Color(1.0f, 0.0f, 0.0f, 0.33f), new Color(0.0f, 1.0f, 0.0f, 0.33f), new Color(0.0f, 1.0f, 1.0f, 0.33f), };
90 
94  @NotNull
95  private final Icon emptySquareIcon;
96 
101  @NotNull
102  private final Point offset = new Point();
103 
109  @Nullable
110  private SoftReference<BufferedImage> backBufferRef;
111 
115  @NotNull
117 
121  @NotNull
122  private final FilterState filterState = new FilterState();
123 
127  @NotNull
129 
134  @NotNull
136 
137  @Override
138  public void configChanged(@NotNull final FilterConfigChangeType filterConfigChangeType, @NotNull final FilterConfig<?, ?> filterConfig) {
139  forceRepaint();
140  }
141 
142  };
143 
156  public FlatMapRenderer(@NotNull final MapViewSettings mapViewSettings, @NotNull final FilterControl<GameObject, MapArchObject, Archetype> filterControl, @NotNull final MapModel<GameObject, MapArchObject, Archetype> mapModel, @NotNull final MapGrid mapGrid, @NotNull final GridMapSquarePainter gridMapSquarePainter, @NotNull final GameObjectParser<GameObject, MapArchObject, Archetype> gameObjectParser, @NotNull final ResourceIcons resourceIcons, @NotNull final SmoothingRenderer smoothingRenderer) {
157  super(mapViewSettings, mapModel, mapGrid, 32, gridMapSquarePainter, gameObjectParser);
158  this.mapModel = mapModel;
159  emptySquareIcon = resourceIcons.getResourceIcon(ResourceIcons.SQUARE_EMPTY);
160  this.filterControl = filterControl;
161  this.mapViewSettings = mapViewSettings;
162  this.smoothingRenderer = smoothingRenderer;
163  init();
164  this.filterControl.addConfigListener(filterConfigListener);
165  }
166 
167  @Override
168  public void closeNotify() {
169  super.closeNotify();
170  filterControl.removeConfigListener(filterConfigListener);
171  }
172 
173  @Override
174  protected void updateSquare(@NotNull final Point point) {
175  if (!mapModel.getMapArchObject().isPointValid(point)) {
176  return;
177  }
178 
179  final Image backBuffer = getBackBufferImage();
180  if (backBuffer == null) {
181  return;
182  }
183 
184  final Graphics g = backBuffer.getGraphics();
185  try {
187  paintSquareGrid(g, point);
188  paintSquareSelection(g, point);
189  } finally {
190  g.dispose();
191  }
192  }
193 
194  @Override
195  protected void updateSquares(@NotNull final Rectangle rectangle) {
196  final Point point = new Point();
197  if (mapViewSettings.isSmoothing()) {
198  for (point.x = rectangle.x - 1; point.x < rectangle.x + rectangle.width + 1; point.x++) {
199  for (point.y = rectangle.y - 1; point.y < rectangle.y + rectangle.height + 1; point.y++) {
200  updateSquare(point);
201  }
202  }
203  } else {
204  for (point.x = rectangle.x; point.x < rectangle.x + rectangle.width; point.x++) {
205  for (point.y = rectangle.y; point.y < rectangle.y + rectangle.height; point.y++) {
206  updateSquare(point);
207  }
208  }
209  }
210  }
211 
212  @Override
213  protected void updateAll() {
214  final Image backBuffer = getBackBufferImage();
215  if (backBuffer == null) {
216  return;
217  }
218 
219  final Graphics graphics = backBuffer.getGraphics();
220  try {
221  paintComponent(graphics, false, false);
222  } finally {
223  graphics.dispose();
224  }
225  }
226 
227  @Override
228  public void paintComponent(@NotNull final Graphics g) {
229  final BufferedImage backBuffer = getBackBufferImage();
230  if (backBuffer != null) {
231  final int w = backBuffer.getWidth();
232  final int h = backBuffer.getHeight();
233  g.drawImage(backBuffer, 0, 0, w, h, 0, 0, w, h, null);
234  } else {
235  paintComponent(g, false, true);
236  }
237  }
238 
239  @Override
240  protected void resizeBackBuffer(@NotNull final Dimension size) {
241  final RenderedImage backBuffer = getBackBufferImage();
242  if (backBuffer != null && backBuffer.getWidth() == size.width && backBuffer.getHeight() == size.height) {
243  return;
244  }
245 
246  backBufferRef = null;
247 
248  if (LOG.isDebugEnabled()) {
249  LOG.debug("Creating a backbuffer of size " + size.width + "x" + size.height + ".");
250  }
251  final BufferedImage newBackBuffer;
252  //The backbuffer is optional
253  //noinspection ErrorNotRethrown
254  try {
255  newBackBuffer = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
256  } catch (final OutOfMemoryError ignore) {
257  if (LOG.isDebugEnabled()) {
258  LOG.debug("out of memory creating new back buffer");
259  }
260  return;
261  }
262  final Graphics g = newBackBuffer.getGraphics();
263  try {
264  g.setColor(getBackground());
265  g.fillRect(0, 0, size.width, size.height);
266  } finally {
267  g.dispose();
268  }
269  backBufferRef = new SoftReference<>(newBackBuffer);
270  }
271 
272  @Override
273  protected void paintSquare(@NotNull final Graphics g, final int x, final int y, @NotNull final MapSquare<GameObject, MapArchObject, Archetype> square) {
274  filterControl.newSquare(filterState);
275  if (square.isEmpty()) {
276  emptySquareIcon.paintIcon(this, g, x, y);
277  } else {
279  if (mapViewSettings.isSmoothing()) {
280  final int borderOffsetX = getBorderOffsetX();
281  final int borderOffsetY = getBorderOffsetY();
282  int layer = -1;
283  for (final GameObject node : square) {
284  if (node.getAttributeInt(GameObject.INVISIBLE, true) == 0) {
285  layer++;
286  }
287  filterControl.objectInSquare(filterState, node);
288  if (filterControl.canShow(node) && mapViewSettings.isEditType(node)) {
289  paintGameObject(g, x, y, node);
290  if (node.getAttributeInt(GameObject.SMOOTHLEVEL, true) > 0) {
291  smoothingRenderer.paintSmooth(g, square.getMapLocation(), node.getAttributeInt(GameObject.SMOOTHLEVEL, true), layer, false, borderOffsetX, borderOffsetY);
292  }
293  }
294  }
295  if (layer > -1) {
296  smoothingRenderer.paintSmooth(g, square.getMapLocation(), 1, layer + 1, true, borderOffsetX, borderOffsetY);
297  }
298  } else {
299  for (final GameObject node : square) {
300  filterControl.objectInSquare(filterState, node);
301  if (filterControl.canShow(node) && mapViewSettings.isEditType(node)) {
302  paintGameObject(g, x, y, node);
303  }
304  }
305  }
306  }
307  for (int i = 0; i < FilterControl.MAX_HIGHLIGHT; i++) {
308  if (filterControl.isHighlightedSquare(filterState, i)) {
309  final Color color = g.getColor();
310  g.setColor(highLightMask[i]);
312  g.setColor(color);
313  }
314  }
315  }
316 
324  private void paintGameObject(@NotNull final Graphics g, final int x, final int y, @NotNull final net.sf.gridarta.model.gameobject.GameObject<GameObject, MapArchObject, Archetype> node) {
325  final ImageIcon img = node.getNormalImage();
326  if (!node.isMulti() || (img.getIconWidth() == IGUIConstants.SQUARE_WIDTH && img.getIconHeight() == IGUIConstants.SQUARE_HEIGHT)) {
327  offset.x = 0;
328  offset.y = 0;
329  } else {
330  // this is an oversized image, so it must be shifted
331  // XXX: it must also be clipped to not overwrite filter information
332  offset.x = IGUIConstants.SQUARE_WIDTH * (node.getArchetype().getMultiX() - node.getMinX());
333  offset.y = IGUIConstants.SQUARE_HEIGHT * (node.getArchetype().getMultiY() - node.getMinY());
334  }
335  g.drawImage(img.getImage(), x, y, x + IGUIConstants.SQUARE_WIDTH, y + IGUIConstants.SQUARE_HEIGHT, offset.x, offset.y, offset.x + IGUIConstants.SQUARE_WIDTH, offset.y + IGUIConstants.SQUARE_HEIGHT, this);
336  }
337 
345  @Nullable
346  private BufferedImage getBackBufferImage() {
347  if (backBufferRef == null) {
348  return null;
349  }
350 
351  final BufferedImage backBuffer = backBufferRef.get();
352  if (backBuffer == null) {
353  if (LOG.isDebugEnabled()) {
354  LOG.debug("lost back buffer");
355  }
356  backBufferRef = null;
357  return null;
358  }
359 
360  return backBuffer;
361  }
362 
363 }
A MapModel reflects the data of a map.
Definition: MapModel.java:75
Graphical User Interface of Gridarta.
Reading and writing of maps, handling of paths.
static final String SMOOTHLEVEL
The name of the "smoothlevel" attribute.
Definition: GameObject.java:70
void newSquare(@NotNull FilterState filterState)
void paintSquareGrid(@NotNull final Graphics graphics, @NotNull final Point point)
Paints the grid for one square.
int SQUARE_HEIGHT
The height of a square in pixels.
void paintSquareSelection(@NotNull final Graphics graphics, @NotNull final Point point)
Paints the selection for one square.
MapArchObject contains the specific meta data about a map that is stored in the map-arch, at the very beginning of the map file.
Handles the Crossfire variants of GameObjects and Archetypes.
Interface for classes that read or write GameObject instances.
boolean isEditType(int editType)
Get information on the current state of edit type.
final Color [] highLightMask
The colors for highlighting.
void forceRepaint()
Repaint the view because some view parameters may have changed.
Renderer for smoothed faces as used by Crossfire.
final Point offset
The offset for painting the map contents.
final Icon emptySquareIcon
The Icon for painting empty map squares.
boolean isSmoothing()
Returns the smoothing setting.
final FilterControl< GameObject, MapArchObject, Archetype > filterControl
The FilterControl for filtering painted game objects.
Base package of all Gridarta classes.
final MapModel< GameObject, MapArchObject, Archetype > mapModel
The MapModel to render.
Reflects a game object (object on a map).
Definition: GameObject.java:36
void paintSquare(@NotNull final Graphics g, final int x, final int y, @NotNull final MapSquare< GameObject, MapArchObject, Archetype > square)
BufferedImage getBackBufferImage()
Get the back buffer image for the map.
Container for settings that affect the rendering of maps.
MapSquare< G, A, R > getMapSquare(@NotNull Point pos)
Get the square at a specified location.
GameObjects are the objects based on Archetypes found on maps.
boolean canShow(@NotNull G gameObject)
SoftReference< BufferedImage > backBufferRef
The back buffer for this map.
boolean isHighlightedSquare(@NotNull FilterState filterState, int path)
2D-Grid containing flags for selection, pre-selection, cursor, warnings and errors.
Definition: MapGrid.java:45
Defines common UI constants used in different dialogs and all used icon files.
The filter package contains the classes for Filters.
Definition: BtnPopup.java:20
final FilterState filterState
The filter state instance for this map renderer.
A AbstractFlatMapRenderer to render map files.
final GameObjectParser< G, A, R > gameObjectParser
The GameObjectParser for creating tooltip information or.
Base classes for rendering maps.
void paintGameObject(@NotNull final Graphics g, final int x, final int y, @NotNull final net.sf.gridarta.model.gameobject.GameObject< GameObject, MapArchObject, Archetype > node)
Paints one game object.
Main package of Gridarta4Crossfire, contains all classes specific to the Crossfire version of the Gri...
static final String INVISIBLE
The name of the "invisible" attribute.
Definition: GameObject.java:64
void objectInSquare(@NotNull FilterState filterState, @NotNull G gameObject)
FlatMapRenderer(@NotNull final MapViewSettings mapViewSettings, @NotNull final FilterControl< GameObject, MapArchObject, Archetype > filterControl, @NotNull final MapModel< GameObject, MapArchObject, Archetype > mapModel, @NotNull final MapGrid mapGrid, @NotNull final GridMapSquarePainter gridMapSquarePainter, @NotNull final GameObjectParser< GameObject, MapArchObject, Archetype > gameObjectParser, @NotNull final ResourceIcons resourceIcons, @NotNull final SmoothingRenderer smoothingRenderer)
Creates a new instance.
A getMapArchObject()
Returns the Map Arch Object with the meta information about the map.
final FilterConfigListener filterConfigListener
The FilterConfigListener attached to filterControl to repaint all after config changes.
static final Category LOG
The Logger for printing log messages.
Creates ImageIcon instances from resources.
void removeConfigListener(@NotNull FilterConfigListener listener)
Removes a FilterConfigListener to be notified about changes.
final GridMapSquarePainter gridMapSquarePainter
The GridMapSquarePainter to use.
final MapViewSettings mapViewSettings
The map view settings instance.
Interface for filter configurations.
final SmoothingRenderer smoothingRenderer
The SmoothingRenderer for rendering smoothed faces.
int SQUARE_WIDTH
The width of a square in pixels.
void paintSmooth(@NotNull final Graphics graphics, @NotNull final Point pos, final int level, final int firstLayer, final boolean allLayers, final int borderOffsetX, final int borderOffsetY)
Draw the smoothing information at given position of map, for a given limit smoothlevel, at a given layer.
Interface for listeners interested in FilterConfig related changes.
The highlighted state while using a FilterControl instance.