Gridarta Editor
SmoothingRenderer.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.Graphics;
23 import java.awt.Point;
24 import javax.swing.ImageIcon;
34 import org.jetbrains.annotations.NotNull;
35 
41 public class SmoothingRenderer {
42 
43  @NotNull
44  private static final int[] DX = { 1, 2, 2, 2, 1, 0, 0, 0, };
45 
46  @NotNull
47  private static final int[] DY = { 0, 0, 1, 2, 2, 2, 1, 0, };
48 
49  @NotNull
50  private static final int[] B_WEIGHTS = { 2, 0, 4, 0, 8, 0, 1, 0, };
51 
52  @NotNull
53  private static final int[] C_WEIGHTS = { 0, 2, 0, 4, 0, 8, 0, 1, };
54 
55  @NotNull
56  private static final int[] BC_EXCLUDE = { 1 + 2, /*north exclude northwest (bit0) and northeast(bit1)*/
57  0, 2 + 4, /*east exclude northeast and southeast*/
58  0, 4 + 8, /*and so on*/
59  0, 8 + 1, 0 };
60 
64  @NotNull
66 
70  @NotNull
71  private final SmoothFaces smoothFaces;
72 
76  @NotNull
78 
79  @NotNull
80  private final net.sf.gridarta.model.gameobject.GameObject<?, ?, ?>[][] layerNode = new net.sf.gridarta.model.gameobject.GameObject<?, ?, ?>[3][3];
81 
82  @NotNull
83  private final int[] sLevels = new int[8];
84 
85  @NotNull
86  private final FaceObject[] sFaces = new FaceObject[8];
87 
95  protected SmoothingRenderer(@NotNull final MapModel<GameObject, MapArchObject, Archetype> mapModel, @NotNull final SmoothFaces smoothFaces, @NotNull final FaceObjectProviders faceObjectProviders) {
96  this.mapModel = mapModel;
97  this.smoothFaces = smoothFaces;
98  this.faceObjectProviders = faceObjectProviders;
99  }
100 
115  public 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) {
116  int layer = firstLayer;
117  while (true) {
118  final MapArchObject mapArchObject = mapModel.getMapArchObject();
119  boolean foundLayer = false;
120  final Point where = new Point();
121  for (int deltaX = -1; deltaX <= 1; deltaX++) {
122  where.x = pos.x + deltaX;
123  for (int deltaY = -1; deltaY <= 1; deltaY++) {
124  where.y = pos.y + deltaY;
125  //false warning: cannot annotate with @Nullable
126  //noinspection AssignmentToNull
127  layerNode[deltaX + 1][deltaY + 1] = null;
128  if (mapArchObject.isPointValid(where)) {
129  int currentLayer = -1;
130  for (final net.sf.gridarta.model.gameobject.GameObject<GameObject, MapArchObject, Archetype> node : mapModel.getMapSquare(where)) {
131  if (node.getAttributeInt(GameObject.INVISIBLE, true) == 0) {
132  currentLayer++;
133  if (currentLayer == layer) {
134  foundLayer = true;
135  if (node.getAttributeInt(GameObject.SMOOTHLEVEL, true) > 0) {
136  layerNode[deltaX + 1][deltaY + 1] = node;
137  }
138  break;
139  }
140  }
141  }
142  }
143  }
144  }
145 
146  /*surrounding nodes having smoothlevel >0 found*/
147  /*below is ripped and adapted from sdl client smooth renderer*/
148  for (int i = 0; i < 8; i++) {
149  final net.sf.gridarta.model.gameobject.GameObject<?, ?, ?> node = layerNode[DX[i]][DY[i]];
150  if (node == null) {
151  sLevels[i] = 0;
152  //false warning: cannot annotate with @Nullable
153  //noinspection AssignmentToNull
154  sFaces[i] = null; /*black picture*/
155  } else {
156  final int smoothlevel = node.getAttributeInt(GameObject.SMOOTHLEVEL, true);
157  if (smoothlevel <= level) {
158  sLevels[i] = 0;
159  //false warning: cannot annotate with @Nullable
160  //noinspection AssignmentToNull
161  sFaces[i] = null; /*black picture*/
162  } else {
163  sLevels[i] = smoothlevel;
164  sFaces[i] = smoothFaces.getSmoothFace(node);
165  }
166  }
167  }
168 
169  /* ok, now we have a list of smoothlevel higher than current square.
170  * there are at most 8 different levels. so... let's check 8 times
171  * for the lowest one (we draw from bottom to top!).
172  */
173  final boolean[] partDone = { false, false, false, false, false, false, false, false, };
174  while (true) {
175  int lowest = -1;
176  for (int i = 0; i < 8; i++) {
177  if (sLevels[i] > 0 && !partDone[i] && (lowest < 0 || sLevels[i] < sLevels[lowest])) {
178  lowest = i;
179  }
180  }
181  if (lowest < 0) {
182  /*no more smooth to do on this square*/
183  /*here we know 'what' to smooth*/
184  break;
185  }
186  final NamedObject smoothFace = sFaces[lowest];
187  /* we need to calculate the weight for border and weight for corners.
188  * then we 'mark done' the corresponding squares
189  */
190  /*first, the border, which may exclude some corners*/
191  int weight = 0;
192  int weightC = 15;
193  for (int i = 0; i < 8; i++) { /*check all nearby squares*/
194  if (sLevels[i] == sLevels[lowest] && sFaces[i] == smoothFace) {
195  partDone[i] = true;
196  weight += B_WEIGHTS[i];
197  weightC &= ~BC_EXCLUDE[i];
198  } else {
199  /*must remove the weight of a corner if not in smoothing*/
200  weightC &= ~C_WEIGHTS[i];
201  }
202  }
203  if (smoothFace == null) {
204  continue; /*Can't smooth black*/
205  }
206  /* now, it's quite easy. We must draw using a 32x32 part of
207  * the picture smooth face.
208  * This part is located using the 2 weights calculated:
209  * (32*weight,0) and (32*weightC,32)
210  */
211  final ImageIcon img = faceObjectProviders.getDisplayIcon(smoothFace);
212  if (weight > 0) {
213  drawImage(graphics, pos, borderOffsetX, borderOffsetY, IGUIConstants.SQUARE_WIDTH * weight, 0, img);
214  }
215  if (weightC > 0) {
216  drawImage(graphics, pos, borderOffsetX, borderOffsetY, IGUIConstants.SQUARE_WIDTH * weightC, IGUIConstants.SQUARE_HEIGHT, img);
217  }
218  } /*while there's some smooth to do*/
219 
220  if (!allLayers || !foundLayer) {
221  break;
222  }
223 
224  layer++;
225  }
226  }
227 
228  private void drawImage(@NotNull final Graphics graphics, @NotNull final Point pos, final int borderOffsetX, final int borderOffsetY, final int srcX, final int srcY, @NotNull final ImageIcon img) {
229  graphics.drawImage(img.getImage(), borderOffsetX + pos.x * IGUIConstants.SQUARE_WIDTH, borderOffsetY + pos.y * IGUIConstants.SQUARE_HEIGHT, borderOffsetX + pos.x * IGUIConstants.SQUARE_WIDTH + IGUIConstants.SQUARE_WIDTH, borderOffsetY + pos.y * IGUIConstants.SQUARE_HEIGHT + IGUIConstants.SQUARE_HEIGHT, srcX, srcY, srcX + IGUIConstants.SQUARE_WIDTH, srcY + IGUIConstants.SQUARE_HEIGHT, null);
230  }
231 
232 }
The data package contains classes for handling data that is organized in a tree.
FaceObject getSmoothFace(@NotNull final GameObject<?, ?, ?> gameObject)
Returns the smooth faces for a GameObject.
A MapModel reflects the data of a map.
Definition: MapModel.java:75
static final String SMOOTHLEVEL
The name of the "smoothlevel" attribute.
Definition: GameObject.java:70
int SQUARE_HEIGHT
The height of a square in pixels.
Common interface for FaceObject.
Definition: FaceObject.java:30
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.
void drawImage(@NotNull final Graphics graphics, @NotNull final Point pos, final int borderOffsetX, final int borderOffsetY, final int srcX, final int srcY, @NotNull final ImageIcon img)
Renderer for smoothed faces as used by Crossfire.
ImageIcon getDisplayIcon(@NotNull final NamedObject namedObject)
Returns the display icon for a NamedObject.
boolean isPointValid(@Nullable final Point pos)
Checks whether the given coordinate is within map bounds.
Base package of all Gridarta classes.
Reflects a game object (object on a map).
Definition: GameObject.java:36
Collection of all smoothing information.
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.
Defines common UI constants used in different dialogs and all used icon files.
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
SmoothingRenderer(@NotNull final MapModel< GameObject, MapArchObject, Archetype > mapModel, @NotNull final SmoothFaces smoothFaces, @NotNull final FaceObjectProviders faceObjectProviders)
Creates a new instance.
A getMapArchObject()
Returns the Map Arch Object with the meta information about the map.
Provider for faces of GameObjects and Archetypes.
The face is the appearance of an object.
final FaceObjectProviders faceObjectProviders
The FaceObjectProviders for looking up faces.
final MapModel< GameObject, MapArchObject, Archetype > mapModel
The MapModel to render.
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.
final net.sf.gridarta.model.gameobject.GameObject<?, ?, ?> [][] layerNode