Crossfire JXClient, Trunk  R20561
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-2010 Andreas Kirschbaum.
20  */
21 
22 package com.realtime.crossfire.jxclient.gui.map;
23 
29 import java.awt.Graphics;
30 import java.util.Arrays;
31 import javax.swing.ImageIcon;
32 import org.jetbrains.annotations.NotNull;
33 
39 public class SmoothingRenderer {
40 
44  private static final int BORDER_WEST = 1;
45 
49  private static final int BORDER_NORTH = 2;
50 
54  private static final int BORDER_EAST = 4;
55 
59  private static final int BORDER_SOUTH = 8;
60 
64  private static final int CORNER_NORTHWEST = 1;
65 
69  private static final int CORNER_NORTHEAST = 2;
70 
74  private static final int CORNER_SOUTHEAST = 4;
75 
79  private static final int CORNER_SOUTHWEST = 8;
80 
84  @NotNull
85  private static final int[] DX = {
86  1,
87  2,
88  2,
89  2,
90  1,
91  0,
92  0,
93  0,
94  };
95 
99  @NotNull
100  private static final int[] DY = {
101  0,
102  0,
103  1,
104  2,
105  2,
106  2,
107  1,
108  0,
109  };
110 
115  @NotNull
116  private static final int[] BORDER_WEIGHT = {
117  BORDER_NORTH,
118  0,
119  BORDER_EAST,
120  0,
121  BORDER_SOUTH,
122  0,
123  BORDER_WEST,
124  0,
125  };
126 
131  @NotNull
132  private static final int[] CORNER_WEIGHT = {
133  0,
135  0,
137  0,
139  0,
141  };
142 
146  @NotNull
147  private static final int[] BORDER_CORNER_EXCLUDE = {
148  CORNER_NORTHWEST+CORNER_NORTHEAST,
149  0,
150  CORNER_NORTHEAST+CORNER_SOUTHEAST,
151  0,
152  CORNER_SOUTHEAST+CORNER_SOUTHWEST,
153  0,
154  CORNER_SOUTHWEST+CORNER_NORTHWEST,
155  0
156  };
157 
161  @NotNull
162  private final SmoothFaces smoothFaces;
163 
167  @NotNull
169 
174  @NotNull
175  private final CfMapSquare[][] layerNode = new CfMapSquare[3][3];
176 
181  @NotNull
182  private final int[] smoothValue = new int[8];
183 
188  @NotNull
189  private final int[] smoothFace = new int[8];
190 
194  @NotNull
195  private final boolean[] done = new boolean[8];
196 
200  @NotNull
201  private final boolean[] isUnknownImage = new boolean[1];
202 
208  protected SmoothingRenderer(@NotNull final SmoothFaces smoothFaces, @NotNull final FacesProvider facesProvider) {
209  this.smoothFaces = smoothFaces;
210  this.facesProvider = facesProvider;
211  }
212 
226  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) {
227  final int level = map.getSmooth(x, y, layer);
228  if (level <= 0) {
229  return;
230  }
231  for (int deltaX = 0; deltaX <= 2; deltaX++) {
232  for (int deltaY = 0; deltaY <= 2; deltaY++) {
233  if (deltaX != 0 || deltaY != 0) {
234  final CfMapSquare mapSquare = map.getMapSquare(x+deltaX-1, y+deltaY-1);
235  //false warning: cannot annotate with @Nullable
236  //noinspection AssignmentToNull
237  layerNode[deltaX][deltaY] = mapSquare.getSmooth(layer) > 0 ? mapSquare : null;
238  }
239  }
240  }
241 
242  for (int i = 0; i < 8; i++) {
243  final CfMapSquare node = layerNode[DX[i]][DY[i]];
244  if (node == null) {
245  smoothValue[i] = 0;
246  smoothFace[i] = 0;
247  } else {
248  final int smoothlevel = node.getSmooth(layer);
249  if (smoothlevel <= level) {
250  smoothValue[i] = 0;
251  smoothFace[i] = 0;
252  } else {
253  smoothValue[i] = smoothlevel;
254  final Face nodeFace = node.getFace(layer);
255  smoothFace[i] = nodeFace == null ? 0 : smoothFaces.getSmoothFace(nodeFace.getFaceNum());
256  }
257  }
258  }
259 
260  // Now we have a list of smoothlevel higher than current square. There
261  // are at most 8 different levels. so... let's check 8 times for the
262  // lowest one (we draw from bottom to top!).
263  Arrays.fill(done, false);
264  while (true) {
265  int lowest = -1;
266  for (int i = 0; i < 8; i++) {
267  if (smoothValue[i] > 0 && !done[i] && (lowest < 0 || smoothValue[i] < smoothValue[lowest])) {
268  lowest = i;
269  }
270  }
271  if (lowest < 0) {
272  // No more smooth to do on this square here we know 'what' to
273  // smooth.
274  break;
275  }
276  final int currentSmoothFace = smoothFace[lowest];
277  // We need to calculate the weight for border and weight for
278  // corners. Then we 'mark done' the corresponding squares.
279  // First, the border, which may exclude some corners.
280  int weight = 0;
281  int weightC = 15;
282  for (int i = 0; i < 8; i++) {
283  if (smoothValue[i] == smoothValue[lowest] && smoothFace[i] == currentSmoothFace) {
284  done[i] = true;
285  weight += BORDER_WEIGHT[i];
286  weightC &= ~BORDER_CORNER_EXCLUDE[i];
287  } else {
288  weightC &= ~CORNER_WEIGHT[i];
289  }
290  }
291  if (currentSmoothFace == 0) {
292  continue;
293  }
294 
295  final ImageIcon imageIcon = facesProvider.getImageIcon(currentSmoothFace, isUnknownImage);
296  if (isUnknownImage[0]) {
297  map.squarePendingFace(x, y, currentSmoothFace);
298  } else {
299  if (weight > 0) {
300  drawImage(graphics, px, py, tileSize*weight, 0, imageIcon, tileSize);
301  }
302  if (weightC > 0) {
303  drawImage(graphics, px, py, tileSize*weightC, tileSize, imageIcon, tileSize);
304  }
305  }
306  }
307  }
308 
320  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) {
321  graphics.drawImage(imageIcon.getImage(), dstX, dstY, dstX+tileSize, dstY+tileSize, srcX, srcY, srcX+tileSize, srcY+tileSize, null);
322  }
323 
324 }
static final int [] DY
Y offset for map coordinate calculation.
static final int CORNER_SOUTHWEST
Corner weight for southwest.
Represents a square in a CfMap.
int getSmooth(final int layer)
Returns the smooth value of this square.
Represents a map (as seen by the client).
Definition: CfMap.java:45
static final int [] CORNER_WEIGHT
Weight (x coordinate) in smoothing face of a corner.
final FacesProvider facesProvider
The FacesProvider for looking up faces.
ImageIcon getImageIcon(int faceNum, @Nullable boolean[] isUnknownImage)
Returns the face for a face ID.
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)
Draws a.
final SmoothFaces smoothFaces
The SmoothFaces to use.
final CfMapSquare [][] layerNode
Surrounding CfMapSquaremap squares} having non-zero smooth levels.
Implements the map model which is shown in the map and magic map views.
Definition: CfMap.java:22
final int [] smoothFace
Face index of the smooth face corresponding to layerNode.
SmoothingRenderer(@NotNull final SmoothFaces smoothFaces, @NotNull final FacesProvider facesProvider)
Creates a new instance.
Manages image information ("faces") needed to display the map view, items, and spell icons...
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.
static final int [] DX
X offset for map coordinate calculation.
static final int BORDER_EAST
Border weight for east.
static final int BORDER_WEST
Border weight for west.
static final int BORDER_NORTH
Border weight for north.
static final int [] BORDER_CORNER_EXCLUDE
Corner excludes due to borders.
int getSmoothFace(final int face)
Returns the smoothing face associated with a given face.
final boolean [] done
Marks the indexes that have been painted.
static final int CORNER_NORTHWEST
Corner weight for northwest.
static final int CORNER_NORTHEAST
Corner weight for northeast.
Renderer for painting smoothed faces into map views.
Face getFace(final int layer)
Returns the face of a layer.
static final int [] BORDER_WEIGHT
Weight (x coordinate) in smoothing face of a corner.
final int [] smoothValue
Smooth values corresponding to layerNode.
static final int CORNER_SOUTHEAST
Corner weight for southeast.
static final int BORDER_SOUTH
Border weight for south.
int getFaceNum()
Returns the unique face id.
Definition: Face.java:105
Maintains smoothing information received from the Crossfire server.