Crossfire JXClient, Trunk
SmoothingRenderer.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-2017,2019-2023 Andreas Kirschbaum
20  * Copyright (C) 2010-2012,2014-2018,2020-2023 Nicolas Weeger
21  */
22 
23 package com.realtime.crossfire.jxclient.gui.map;
24 
30 import java.awt.Graphics;
31 import java.util.Arrays;
32 import java.util.concurrent.atomic.AtomicBoolean;
33 import javax.swing.ImageIcon;
34 import org.jetbrains.annotations.NotNull;
35 import org.jetbrains.annotations.Nullable;
36 
42 public class SmoothingRenderer {
43 
47  private static final int BORDER_WEST = 1;
48 
52  private static final int BORDER_NORTH = 2;
53 
57  private static final int BORDER_EAST = 4;
58 
62  private static final int BORDER_SOUTH = 8;
63 
67  private static final int CORNER_NORTHWEST = 1;
68 
72  private static final int CORNER_NORTHEAST = 2;
73 
77  private static final int CORNER_SOUTHEAST = 4;
78 
82  private static final int CORNER_SOUTHWEST = 8;
83 
87  private static final int @NotNull [] DX = {1, 2, 2, 2, 1, 0, 0, 0,};
88 
92  private static final int @NotNull [] DY = {0, 0, 1, 2, 2, 2, 1, 0,};
93 
98  private static final int @NotNull [] BORDER_WEIGHT = {BORDER_NORTH, 0, BORDER_EAST, 0, BORDER_SOUTH, 0, BORDER_WEST, 0,};
99 
104  private static final int @NotNull [] CORNER_WEIGHT = {0, CORNER_NORTHEAST, 0, CORNER_SOUTHEAST, 0, CORNER_SOUTHWEST, 0, CORNER_NORTHWEST,};
105 
110 
114  @NotNull
115  private final SmoothFaces smoothFaces;
116 
120  @NotNull
122 
127  @Nullable
128  private final CfMapSquare @NotNull [] @NotNull [] layerNode = new CfMapSquare[3][3];
129 
134  private final int @NotNull [] smoothValue = new int[8];
135 
140  private final int @NotNull [] smoothFace = new int[8];
141 
145  private final boolean @NotNull [] done = new boolean[8];
146 
150  @NotNull
151  private final AtomicBoolean isUnknownImage = new AtomicBoolean();
152 
158  protected SmoothingRenderer(@NotNull final SmoothFaces smoothFaces, @NotNull final FacesProvider facesProvider) {
159  this.smoothFaces = smoothFaces;
160  this.facesProvider = facesProvider;
161  }
162 
176  public 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) {
177  for (int deltaX = 0; deltaX <= 2; deltaX++) {
178  for (int deltaY = 0; deltaY <= 2; deltaY++) {
179  if (deltaX != 1 || deltaY != 1) {
180  final CfMapSquare mapSquare = map.getMapSquare(x+deltaX-1, y+deltaY-1);
181  //noinspection AssignmentToNull,ConstantConditions
182  layerNode[deltaX][deltaY] = mapSquare.getSmooth(layer) > 0 ? mapSquare : null;
183  }
184  }
185  }
186 
187  final int level = map.getSmooth(x, y, layer);
188 
189  for (int i = 0; i < 8; i++) {
190  final CfMapSquare node = layerNode[DX[i]][DY[i]];
191  //noinspection ConstantConditions
192  if (node == null) {
193  smoothValue[i] = 0;
194  smoothFace[i] = 0;
195  } else {
196  final int smoothlevel = node.getSmooth(layer);
197  if (smoothlevel <= level) {
198  smoothValue[i] = 0;
199  smoothFace[i] = 0;
200  } else {
201  smoothValue[i] = smoothlevel;
202  final Face nodeFace = node.getFace(layer);
203  smoothFace[i] = nodeFace == null ? 0 : smoothFaces.getSmoothFace(nodeFace.getFaceNum());
204  }
205  }
206  }
207 
208  // Now we have a list of smoothlevel higher than current square. There
209  // are at most 8 different levels. so... let's check 8 times for the
210  // lowest one (we draw from bottom to top!).
211  Arrays.fill(done, false);
212  while (true) {
213  int lowest = -1;
214  for (int i = 0; i < 8; i++) {
215  if (smoothValue[i] > 0 && !done[i] && (lowest < 0 || smoothValue[i] < smoothValue[lowest])) {
216  lowest = i;
217  }
218  }
219  if (lowest < 0) {
220  // No more smooth to do on this square here we know 'what' to
221  // smooth.
222  break;
223  }
224  final int currentSmoothFace = smoothFace[lowest];
225  // We need to calculate the weight for border and weight for
226  // corners. Then we 'mark done' the corresponding squares.
227  // First, the border, which may exclude some corners.
228  int weight = 0;
229  int weightC = 15;
230  for (int i = 0; i < 8; i++) {
231  if (smoothValue[i] == smoothValue[lowest] && smoothFace[i] == currentSmoothFace) {
232  done[i] = true;
233  weight |= BORDER_WEIGHT[i];
234  weightC &= ~BORDER_CORNER_EXCLUDE[i];
235  } else {
236  weightC &= ~CORNER_WEIGHT[i];
237  }
238  }
239  if (currentSmoothFace == 0) {
240  continue;
241  }
242 
243  final ImageIcon imageIcon = facesProvider.getImageIcon(currentSmoothFace, isUnknownImage);
244  if (isUnknownImage.get()) {
245  map.squarePendingFace(x, y, currentSmoothFace);
246  } else {
247  if (weight != 0) {
248  drawImage(graphics, px, py, tileSize*weight, 0, imageIcon, tileSize);
249  }
250  if (weightC != 0) {
251  drawImage(graphics, px, py, tileSize*weightC, tileSize, imageIcon, tileSize);
252  }
253  }
254  }
255  }
256 
268  private static void drawImage(@NotNull final Graphics graphics, final int dstX, final int dstY, final int srcX, final int srcY, @NotNull final ImageIcon imageIcon, final int tileSize) {
269  graphics.drawImage(imageIcon.getImage(), dstX, dstY, dstX+tileSize, dstY+tileSize, srcX, srcY, srcX+tileSize, srcY+tileSize, null);
270  }
271 
272 }
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.CORNER_SOUTHEAST
static final int CORNER_SOUTHEAST
Definition: SmoothingRenderer.java:77
com.realtime.crossfire.jxclient
com.realtime.crossfire.jxclient.faces.SmoothFaces.getSmoothFace
int getSmoothFace(final int face)
Definition: SmoothFaces.java:46
com.realtime.crossfire.jxclient.map.CfMapSquare.getSmooth
int getSmooth(final int layer)
Definition: CfMapSquare.java:235
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.DX
static final int[] DX
Definition: SmoothingRenderer.java:87
com.realtime.crossfire.jxclient.faces.SmoothFaces
Definition: SmoothFaces.java:33
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.CORNER_NORTHWEST
static final int CORNER_NORTHWEST
Definition: SmoothingRenderer.java:67
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.smoothFace
final int[] smoothFace
Definition: SmoothingRenderer.java:140
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.CORNER_NORTHEAST
static final int CORNER_NORTHEAST
Definition: SmoothingRenderer.java:72
com.realtime.crossfire.jxclient.faces.FacesProvider
Definition: FacesProvider.java:34
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.BORDER_SOUTH
static final int BORDER_SOUTH
Definition: SmoothingRenderer.java:62
com.realtime.crossfire.jxclient.map
Definition: CfMap.java:23
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.BORDER_CORNER_EXCLUDE
static final int[] BORDER_CORNER_EXCLUDE
Definition: SmoothingRenderer.java:109
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer
Definition: SmoothingRenderer.java:42
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.CORNER_SOUTHWEST
static final int CORNER_SOUTHWEST
Definition: SmoothingRenderer.java:82
com.realtime.crossfire.jxclient.map.CfMap
Definition: CfMap.java:46
com.realtime.crossfire.jxclient.faces
Definition: AbstractFaceQueue.java:23
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.BORDER_WEST
static final int BORDER_WEST
Definition: SmoothingRenderer.java:47
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.smoothFaces
final SmoothFaces smoothFaces
Definition: SmoothingRenderer.java:115
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.BORDER_EAST
static final int BORDER_EAST
Definition: SmoothingRenderer.java:57
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.facesProvider
final FacesProvider facesProvider
Definition: SmoothingRenderer.java:121
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.DY
static final int[] DY
Definition: SmoothingRenderer.java:92
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.CORNER_WEIGHT
static final int[] CORNER_WEIGHT
Definition: SmoothingRenderer.java:104
com.realtime.crossfire.jxclient.map.CfMapSquare.getFace
Face getFace(final int layer)
Definition: CfMapSquare.java:278
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.SmoothingRenderer
SmoothingRenderer(@NotNull final SmoothFaces smoothFaces, @NotNull final FacesProvider facesProvider)
Definition: SmoothingRenderer.java:158
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.smoothValue
final int[] smoothValue
Definition: SmoothingRenderer.java:134
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.BORDER_NORTH
static final int BORDER_NORTH
Definition: SmoothingRenderer.java:52
com.realtime.crossfire
com.realtime.crossfire.jxclient.faces.FacesProvider.getImageIcon
ImageIcon getImageIcon(int faceNum, @Nullable AtomicBoolean returnIsUnknownImage)
com.realtime
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.isUnknownImage
final AtomicBoolean isUnknownImage
Definition: SmoothingRenderer.java:151
com
com.realtime.crossfire.jxclient.faces.Face.getFaceNum
int getFaceNum()
Definition: Face.java:105
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.done
final boolean[] done
Definition: SmoothingRenderer.java:145
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.paintSmooth
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)
Definition: SmoothingRenderer.java:176
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.BORDER_WEIGHT
static final int[] BORDER_WEIGHT
Definition: SmoothingRenderer.java:98
com.realtime.crossfire.jxclient.faces.Face
Definition: Face.java:37
com.realtime.crossfire.jxclient.map.CfMapSquare
Definition: CfMapSquare.java:40
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.drawImage
static void drawImage(@NotNull final Graphics graphics, final int dstX, final int dstY, final int srcX, final int srcY, @NotNull final ImageIcon imageIcon, final int tileSize)
Definition: SmoothingRenderer.java:268
com.realtime.crossfire.jxclient.gui.map.SmoothingRenderer.layerNode
final CfMapSquare[][] layerNode
Definition: SmoothingRenderer.java:128