Gridarta Editor
StretchedImageFilter.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2010 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.model.face;
21 
22 import java.awt.Point;
23 import java.awt.Polygon;
24 import java.awt.image.ColorModel;
25 import java.awt.image.ImageFilter;
26 import org.jetbrains.annotations.NotNull;
27 
32 public class StretchedImageFilter extends ImageFilter {
33 
37  private static final ColorModel RGB_DEFAULT_COLOR_MODEL = ColorModel.getRGBdefault();
38 
42  private long stretchFactor;
43 
47  private int width;
48 
49  private int height;
50 
54  @NotNull
55  private int[] raster = new int[0];
56 
57  @NotNull
58  private int[] pixels = new int[0];
59 
60  @NotNull
61  private static final Point[] point = { new Point(), new Point(), new Point(), new Point() };
62 
63  @NotNull
64  private static final Point[] point2 = { new Point(), new Point(), new Point(), new Point() };
65 
66  @NotNull
67  private static final double[] slope = { 0.0, 0.0, 0.0, 0.0 };
68 
69  @NotNull
70  private final int[] stdTileHalfLen = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0 };
71 
72  @NotNull
73  private static final Polygon polygon = new Polygon();
74 
79  public void setStretchedFactor(final long stretchFactor) {
80  this.stretchFactor = stretchFactor;
81  }
82 
83  @Override
84  public void setDimensions(final int width, final int height) {
85  this.width = width;
86  this.height = height;
87  final int newHeight = height + (int) ((stretchFactor >> 24) & 0xff);
88  pixels = new int[width * height];
89  raster = new int[width * newHeight];
90  super.setDimensions(width, newHeight);
91  }
92 
93  @Override
94  public void setHints(final int hints) {
95  super.setHints(COMPLETESCANLINES | TOPDOWNLEFTRIGHT);
96  }
97 
98  @Override
99  public void setPixels(final int x, final int y, final int w, final int h, @NotNull final ColorModel model, @NotNull final byte[] pixels, final int off, final int scansize) {
100  int srcOff = off;
101  int dstOff = y * width + x;
102  for (int yc = 0; yc < h; yc++) {
103  for (int xc = 0; xc < w; xc++) {
104  this.pixels[dstOff++] = model.getRGB(pixels[srcOff++] & 0xff);
105  }
106  srcOff += scansize - w;
107  dstOff += width - w;
108  }
109  }
110 
111  @Override
112  public void setPixels(final int x, final int y, final int w, final int h, @NotNull final ColorModel model, @NotNull final int[] pixels, final int off, final int scansize) {
113  int srcOff = off;
114  int dstOff = y * width + x;
115  for (int yc = 0; yc < h; yc++) {
116  for (int xc = 0; xc < w; xc++) {
117  this.pixels[dstOff++] = model.getRGB(pixels[srcOff++]);
118  }
119  srcOff += scansize - w;
120  dstOff += width - w;
121  }
122  }
123 
124  private static void determineLine(final int idx, final int sx, final int sy, final int ex, final int ey) {
125  point[idx].x = sx;
126  point[idx].y = sy;
127  point2[idx].x = ex;
128  point2[idx].y = ey;
129  final double xDiff = Math.abs(sx - ex);
130  final double yDiff = Math.abs(sy - ey);
131  slope[idx] = xDiff == 0 ? 0.0 : yDiff / xDiff;
132  }
133 
134  private static void determineLines(final int n, final int e, final int s, final int w) {
135  determineLine(0, 2, 10 - w + n, 22, 0);
136  determineLine(1, 2, 12 - w + n, 22, 22 + n - s);
137  determineLine(2, 45, 10 - e + n, 25, 0);
138  determineLine(3, 45, 12 - e + n, 25, 22 + n - s);
139  }
140 
149  public static boolean coordsInTile(final long stretch, final int x, final int y) {
150  final int n = (int) (stretch >> 24) & 0xff;
151  final int e = (int) (stretch >> 16) & 0xff;
152  final int w = (int) (stretch >> 8) & 0xff;
153  final int s = (int) stretch & 0xff;
154  determineLines(n, e, s, w);
155 
156  polygon.reset();
157  polygon.addPoint(point2[0].x - 1, point2[0].y - 1);
158  polygon.addPoint(point2[2].x + 1, point2[2].y - 1);
159  polygon.addPoint(point[2].x + 3, point[2].y - 1);
160  polygon.addPoint(point[3].x + 3, point[3].y + 1);
161  polygon.addPoint(point2[3].x + 1, point2[3].y + 2);
162  polygon.addPoint(point2[1].x - 1, point2[1].y + 2);
163  polygon.addPoint(point[1].x - 3, point[1].y + 1);
164  polygon.addPoint(point[0].x - 3, point[0].y - 1);
165 
166  return polygon.contains(x, y);
167  }
168 
169  private void copyPixelToPixel(final int x, final int y, final int x2, final int y2, final double brightness, final int wd, final int ht, final int wd2, final int ht2, @NotNull final ColorModel model) {
170  if (x < 0 || y < 0 || x2 < 0 || y2 < 0 || x >= wd || x2 >= wd2 || y >= ht || y2 >= ht2) {
171  return;
172  }
173 
174  final int color = model.getRGB(pixels[y * wd + x]);
175 
176  final int a = (color >> 24) & 0xff;
177  if (a == 0) {
178  return;
179  }
180  final int r1 = (color >> 16) & 0xff;
181  final int g1 = (color >> 8) & 0xff;
182  final int b1 = (color >> 0) & 0xff;
183 
184  final int r = Math.min(255, (int) (r1 * brightness));
185  final int g = Math.min(255, (int) (g1 * brightness));
186  final int b = Math.min(255, (int) (b1 * brightness));
187  raster[y2 * wd2 + x2] = (a << 24) | (r << 16) | (g << 8) | (b << 0);
188  }
189 
190  private void copyVerticalLine(final int srcX, final int srcSy, final int srcEy, final int destX, final int destSy, final int destEy, final double brightness, final boolean extra, final int wd, final int ht, final int wd2, final int ht2, @NotNull final ColorModel model) {
191  final int minSrcY = Math.min(srcSy, srcEy);
192  final int maxSrcY = Math.max(srcSy, srcEy);
193  final int minDestY = Math.min(destSy, destEy);
194  final int maxDestY = Math.max(destSy, destEy);
195  final int srcH = maxSrcY - minSrcY;
196  final int destH = maxDestY - minDestY;
197 
198  if (destH == 0) {
199  copyPixelToPixel(srcX, srcH == 0 ? minSrcY : (maxSrcY - minSrcY) / 2, destX, minDestY, brightness, wd, ht, wd2, ht2, model);
200  return;
201  }
202 
203  if (srcH == 0) {
204  final int pixel = model.getRGB(pixels[minSrcY * wd + srcX]);
205  for (int y = minDestY; y <= maxDestY; y++) {
206  raster[y * wd2 + destX] = pixel;
207  }
208  return;
209  }
210 
211  /* The stretching */
212  final double ratio = (double) srcH / (double) destH;
213 
214  for (int y = 0; y <= destH; y++) {
215  final int goY = minDestY + y;
216  final int getY = (int) (minSrcY + (y * ratio));
217  copyPixelToPixel(srcX, getY, destX, goY, brightness, wd, ht, wd2, ht2, model);
218  }
219 
220  if (extra && maxDestY + 1 < ht2) {
221  copyPixelToPixel(srcX, maxSrcY, destX, maxDestY + 1, brightness, wd, ht, wd2, ht2, model);
222  }
223  }
224 
225  private void stretch(final int wd, final int ht, @NotNull final ColorModel model) {
226  final int n = (int) (stretchFactor >> 24) & 0xff;
227  final int e = (int) (stretchFactor >> 16) & 0xff;
228  final int w = (int) (stretchFactor >> 8) & 0xff;
229  final int s = (int) stretchFactor & 0xff;
230 
231  final int wd2 = wd;
232  final int ht2 = ht + n;
233 
234  final boolean flat = n != 0 || e != 0 || w != 0 || s != 0;
235 
236  final double eDark;
237  final double wDark;
238  if (w > e) {
239  wDark = 1.0 - ((w - e) / 25.0);
240 
241  if (n > 0 || s > 0) {
242  eDark = wDark;
243  } else {
244  eDark = 1.0;
245  }
246  } else if (e > w) {
247  eDark = 1.0 + ((e - w) / 25.0);
248 
249  if (s > 0 || n > 0) {
250  wDark = eDark;
251  } else {
252  wDark = 1.0;
253  }
254  } else {
255  eDark = 1.0;
256  wDark = 1.0;
257  }
258 
259  determineLines(n, e, s, w);
260 
261  for (int lnNum = 0; lnNum < 4; lnNum += 2) {
262  final int destSx = point[lnNum].x;
263  final int destSy = point[lnNum].y;
264  final int destEx = point2[lnNum].x;
265  final int destEy = point2[lnNum].y;
266  final double destSlope = slope[lnNum];
267 
268  final int destSy2 = point[lnNum + 1].y;
269  final int destEy2 = point2[lnNum + 1].y;
270  final double destSlope2 = slope[lnNum + 1];
271 
272  final int destYInc = destSy > destEy ? -1 : 1;
273  final int destXInc = destSx > destEx ? -1 : 1;
274  final int destYInc2 = destSy2 > destEy2 ? -1 : 1;
275 
276  int dx = destSx;
277  int dy = destSy;
278  double kicker = 0.0;
279  int y2 = destSy2;
280  double kicker2 = 0.0;
281  boolean atLeastOne = false;
282 
283  while ((destSlope != 0.0 && dx != destEx && dy != destEy) || (!atLeastOne && destSlope == 0.0)) {
284  atLeastOne = true;
285 
286  if (kicker >= 1.0) {
287  kicker -= 1.0;
288  dy += destYInc;
289  }
290 
291  if (kicker2 >= 1.0) {
292  kicker2 -= 1.0;
293  y2 += destYInc2;
294  }
295 
296  final int srcLen = stdTileHalfLen[dx];
297 
298  copyVerticalLine(dx, 11 + srcLen, 11 - srcLen, dx, dy, y2, lnNum < 2 ? wDark : eDark, flat, wd, ht, wd2, ht2, model);
299 
300  dx += destXInc;
301 
302  kicker += destSlope;
303  kicker2 += destSlope2;
304  }
305  }
306 
307  for (int dx = 22; dx < 22 + 2; dx++) {
308  copyVerticalLine(dx, 0, 23, dx, 0, 23 + n - s, wDark, flat, wd, ht, wd2, ht2, model);
309  }
310 
311  for (int dx = 24; dx < 24 + 2; dx++) {
312  copyVerticalLine(dx, 0, 23, dx, 0, 23 + n - s, eDark, flat, wd, ht, wd2, ht2, model);
313  }
314 
315  for (int dx = 0; dx < 2; dx++) {
316  copyPixelToPixel(dx, 11, dx, 11 + n - w, wDark, wd, ht, wd2, ht2, model);
317  }
318 
319  for (int dx = 46; dx < 48; dx++) {
320  copyPixelToPixel(dx, 11, dx, 11 + n - e, eDark, wd, ht, wd2, ht2, model);
321  }
322  }
323 
324  @Override
325  public void imageComplete(final int status) {
326  if (status != IMAGEERROR && status != IMAGEABORTED) {
327  stretch(width, height, RGB_DEFAULT_COLOR_MODEL);
328  super.setPixels(0, 0, width, height + (int) ((stretchFactor >> 24) & 0xff), RGB_DEFAULT_COLOR_MODEL, raster, 0, width);
329  }
330  super.imageComplete(status);
331  }
332 
333 }
static void determineLine(final int idx, final int sx, final int sy, final int ex, final int ey)
void stretch(final int wd, final int ht, @NotNull final ColorModel model)
static void determineLines(final int n, final int e, final int s, final int w)
void setDimensions(final int width, final int height)
int [] raster
The destination image&#39;s pixels.
void copyVerticalLine(final int srcX, final int srcSy, final int srcEy, final int destX, final int destSy, final int destEy, final double brightness, final boolean extra, final int wd, final int ht, final int wd2, final int ht2, @NotNull final ColorModel model)
static final ColorModel RGB_DEFAULT_COLOR_MODEL
The default RGB color model.
void copyPixelToPixel(final int x, final int y, final int x2, final int y2, final double brightness, final int wd, final int ht, final int wd2, final int ht2, @NotNull final ColorModel model)
void setPixels(final int x, final int y, final int w, final int h, @NotNull final ColorModel model, @NotNull final byte[] pixels, final int off, final int scansize)
void setStretchedFactor(final long stretchFactor)
Set the stretch factor for this instance.
An ImageFilter that produces stretched faces.
static boolean coordsInTile(final long stretch, final int x, final int y)
Checks whether the specified coordinates are inside a (possibly stretched) isometric tile...
void setPixels(final int x, final int y, final int w, final int h, @NotNull final ColorModel model, @NotNull final int[] pixels, final int off, final int scansize)