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