Gridarta Editor
AbstractIsoMapRenderer.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.gui.map.renderer;
21 
22 import java.awt.AlphaComposite;
23 import java.awt.Color;
24 import java.awt.Composite;
25 import java.awt.Dimension;
26 import java.awt.Graphics;
27 import java.awt.Graphics2D;
28 import java.awt.Point;
29 import java.awt.Rectangle;
30 import java.awt.geom.AffineTransform;
31 import java.awt.image.BufferedImage;
32 import java.util.Arrays;
33 import java.util.Set;
34 import javax.swing.Icon;
55 import net.sf.gridarta.utils.Size2D;
56 import org.jetbrains.annotations.NotNull;
57 import org.jetbrains.annotations.Nullable;
58 
66 public abstract class AbstractIsoMapRenderer<G extends DefaultIsoGameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>> extends AbstractMapRenderer<G, A, R> {
67 
71  private static final long serialVersionUID = 1L;
72 
76  @NotNull
77  private static final Color BACKGROUND_COLOR = new Color(255, 255, 255, 0);
78 
82  private final int spawnPointTypeNo;
83 
88  @NotNull
89  private final Point borderOffset;
90 
94  @NotNull
95  private final Point origin = new Point();
96 
100  @NotNull
102 
106  @NotNull
107  private Size2D mapSize;
108 
112  @NotNull
113  private final MapGrid mapGrid;
114 
118  @NotNull
119  private final Icon unknownSquareIcon;
120 
124  @NotNull
125  private final Point tmpPoint = new Point();
126 
130  private final Rectangle tmpRec = new Rectangle();
131 
135  @NotNull
137 
141  @NotNull
143 
147  @NotNull
149 
153  @NotNull
155 
159  protected int minYOffset;
160 
164  protected int maxYOffset;
165 
170  @NotNull
171  protected final boolean[] foundSubLayers = new boolean[DefaultIsoGameObject.MAX_SUB_LAYERS];
172 
177  @NotNull
179 
180  @Override
181  public void gridVisibleChanged(final boolean gridVisible) {
182  forceRepaint();
183  }
184 
185  @Override
186  public void lightVisibleChanged(final boolean lightVisible) {
187  forceRepaint();
188  }
189 
190  @Override
191  public void smoothingChanged(final boolean smoothing) {
192  // does not render smoothed faces
193  }
194 
195  @Override
196  public void tileStretchingChanged(final boolean tileStretching) {
197  resizeFromModel();
198  forceRepaint();
199  }
200 
201  @Override
202  public void doubleFacesChanged(final boolean doubleFaces) {
203  forceRepaint();
204  }
205 
206  @Override
207  public void alphaTypeChanged(final int alphaType) {
208  forceRepaint();
209  }
210 
211  @Override
212  public void editTypeChanged(final int editType) {
213  // changed game objects will be rendered
214  }
215 
216  @Override
217  public void autojoinChanged(final boolean autojoin) {
218  // ignore
219  }
220 
221  };
222 
226  @NotNull
228 
229  @Override
230  public void mapSizeChanged(@NotNull final Size2D newSize) {
231  // ignore: will trigger an mapGridChanged() callback
232  }
233 
234  @Override
235  public void mapSquaresChanged(@NotNull final Set<MapSquare<G, A, R>> mapSquares) {
236  repaint(); // TODO: only repaint a specific region
237  }
238 
239  @Override
240  public void mapObjectsChanged(@NotNull final Set<G> gameObjects, @NotNull final Set<G> transientGameObjects) {
241  if (mapViewSettings.isTileStretching()) {
242  boolean resize = false;
243  for (final G gameObject : gameObjects) {
244  if (!gameObject.isStretched(true)) {
245  continue;
246  }
247 
248  if (!resize && gameObject.getAttributeInt(DefaultIsoGameObject.LAYER) == 1) {
249  final int yOffset = gameObject.getAttributeInt(DefaultIsoGameObject.Z);
250 
251  if (yOffset > maxYOffset || yOffset < minYOffset) {
252  resize = true;
253  }
254  }
255 
256  final MapSquare<G, A, R> mapSquare = gameObject.getMapSquare();
257  if (mapSquare == null) {
258  continue;
259  }
260 
261  final MapModel<G, A, R> mapModel = mapSquare.getMapModel();
262  final int subLayer = gameObject.getAttributeInt(DefaultIsoGameObject.SUB_LAYER);
263 
264  for (final Direction direction : Direction.values()) {
265  if (direction.getDz() != 0) {
266  continue;
267  }
268 
269  mapSquare.getMapLocation(tmpPoint, direction.getDx(), direction.getDy());
270  final MapSquare<G, A, R> mapSquareAdjacent;
271  try {
272  mapSquareAdjacent = mapModel.getMapSquare(tmpPoint);
273  } catch (final IndexOutOfBoundsException ignored) {
274  continue;
275  }
276  for (final G gameObjectAdjacent : mapSquareAdjacent) {
277  if (!gameObjectAdjacent.isStretched(true)) {
278  continue;
279  }
280 
281  if (gameObjectAdjacent.getAttributeInt(DefaultIsoGameObject.SUB_LAYER) != subLayer) {
282  continue;
283  }
284 
285  gameObjectAdjacent.refreshStretchFactor();
286  }
287  }
288 
289  gameObject.refreshStretchFactor();
290  }
291 
292  if (resize) {
293  resizeFromModel();
294  }
295  }
296 
297  repaint(); // TODO: only repaint a specific region
298  }
299 
300  @Override
301  public void errorsChanged(@NotNull final ErrorCollector<G, A, R> errors) {
302  // ignore
303  }
304 
305  @Override
306  public void mapFileChanged(@Nullable final MapFile oldMapFile) {
307  // ignore
308  }
309 
310  @Override
311  public void modifiedChanged() {
312  // ignore
313  }
314 
315  };
316 
320  @NotNull
322 
323  @Override
324  public void mapGridChanged(@NotNull final MapGridEvent e) {
325  repaint();
326  }
327 
328  @Override
329  public void mapGridResized(@NotNull final MapGridEvent e) {
330  mapSize = e.getSource().getSize();
331  calculateOrigin();
332  resizeFromModel();
333  repaint();
334  }
335 
336  };
337 
354  protected AbstractIsoMapRenderer(final int spawnPointTypeNo, @NotNull final MapViewSettings mapViewSettings, @NotNull final MapModel<G, A, R> mapModel, @NotNull final MapGrid mapGrid, final int borderOffsetX, final int borderOffsetY, @NotNull final MultiPositionData multiPositionData, @NotNull final IsoMapSquareInfo isoMapSquareInfo, @NotNull final GridMapSquarePainter gridMapSquarePainter, @NotNull final GameObjectParser<G, A, R> gameObjectParser, @NotNull final Icon unknownSquareIcon) {
355  super(mapModel, gameObjectParser);
356  this.spawnPointTypeNo = spawnPointTypeNo;
357  this.mapViewSettings = mapViewSettings;
358  this.multiPositionData = multiPositionData;
359  this.isoMapSquareInfo = isoMapSquareInfo;
360  this.gridMapSquarePainter = gridMapSquarePainter;
361  borderOffset = new Point(borderOffsetX, borderOffsetY);
362  this.mapModel = mapModel;
363  mapSize = this.mapModel.getMapArchObject().getMapSize();
364  this.mapGrid = mapGrid;
365  this.unknownSquareIcon = unknownSquareIcon;
366 
367  mapViewSettings.addMapViewSettingsListener(mapViewSettingsListener);
368 
369  setToolTipText("dummy");
370  setFocusable(true);
371  calculateOrigin();
372  resizeFromModel();
373  mapModel.addMapModelListener(mapModelListener);
374  mapGrid.addMapGridListener(mapGridListener);
375  }
376 
377  @Override
378  public void closeNotify() {
379  mapModel.removeMapModelListener(mapModelListener);
380  mapGrid.removeMapGridListener(mapGridListener);
381  mapViewSettings.removeMapViewSettingsListener(mapViewSettingsListener);
382  }
383 
388  private void calculateOrigin() {
389  origin.setLocation(borderOffset.x + mapSize.getHeight() * isoMapSquareInfo.getXLen2(), borderOffset.y + maxYOffset);
390  }
391 
400  private void setBorderOffset(final int x, final int y) {
401  borderOffset.setLocation(x, y);
402  calculateOrigin();
403  }
404 
405  @NotNull
406  @Override
407  public BufferedImage getFullImage() {
408  // set map dimensions for iso view
409  final int mapWidth = mapSize.getWidth();
410  final int mapHeight = mapSize.getHeight();
411  final int sum = mapWidth + mapHeight;
412  final int viewWidth = sum * isoMapSquareInfo.getXLen2();
413  final int viewHeight = sum * isoMapSquareInfo.getYLen2();
414 
415  // first create a storing place for the image
416  final BufferedImage image = new BufferedImage(viewWidth, viewHeight, BufferedImage.TYPE_INT_ARGB);
417  final Graphics2D graphics = image.createGraphics();
418  graphics.setColor(BACKGROUND_COLOR);
419  graphics.fillRect(0, 0, viewWidth, viewHeight);
420 
421  // paint the map view into the image
422  final Point storeOffset = new Point(borderOffset);
423  setBorderOffset(0, 0);
424 
425  clearBackground(graphics);
426  final Point pos = new Point();
427  for (pos.y = 0; pos.y < mapHeight; pos.y++) {
428  int xStart = origin.x - (pos.y + 1) * isoMapSquareInfo.getXLen2();
429  int yStart = origin.y + pos.y * isoMapSquareInfo.getYLen2();
430  for (pos.x = 0; pos.x < mapWidth; pos.x++) {
431  paintSquare(graphics, xStart, yStart, mapModel.getMapSquare(pos));
432  xStart += isoMapSquareInfo.getXLen2();
433  yStart += isoMapSquareInfo.getYLen2();
434  }
435  }
436 
437  paintMapGrid(graphics);
438  paintMapSelection(graphics);
439 
440  setBorderOffset(storeOffset.x, storeOffset.y);
441  return image;
442  }
443 
444  @Override
445  public void paintComponent(@NotNull final Graphics g) {
446  paintComponent2((Graphics2D) g);
447  }
448 
449  @Override
450  public void forceRepaint() {
451  repaint();
452  }
453 
454  @NotNull
455  @Override
456  public Rectangle getSquareBounds(@NotNull final Point p) {
457  tmpRec.x = origin.x - (p.y + 1) * isoMapSquareInfo.getXLen2() + p.x * isoMapSquareInfo.getXLen2();
458  tmpRec.y = origin.y + p.y * isoMapSquareInfo.getYLen2() + p.x * isoMapSquareInfo.getYLen2();
459  tmpRec.width = isoMapSquareInfo.getXLen();
460  tmpRec.height = isoMapSquareInfo.getYLen();
461  return tmpRec;
462  }
463 
468  protected abstract void clearBackground(@NotNull Graphics g);
469 
477  protected abstract void paintSquare(@NotNull Graphics2D g, int x, int y, @NotNull MapSquare<G, A, R> square);
478 
483  private void paintComponent2(@NotNull final Graphics2D g) {
484  clearBackground(g);
485  final Rectangle rec = getRepaintRec(getVisibleRect());
486  final Point pos = new Point();
487  final Point endPos = rec.getLocation();
488  endPos.translate(rec.width, rec.height);
489  for (pos.y = rec.y; pos.y < endPos.y; pos.y++) {
490  int xStart = origin.x - (pos.y - rec.x + 1) * isoMapSquareInfo.getXLen2();
491  int yStart = origin.y + (pos.y + rec.x) * isoMapSquareInfo.getYLen2();
492  for (pos.x = rec.x; pos.x < endPos.x; pos.x++) {
493  if (g.hitClip(xStart, yStart - isoMapSquareInfo.getYLen() * 4 - minYOffset, isoMapSquareInfo.getXLen(), isoMapSquareInfo.getYLen() * 5 + maxYOffset)) {
494  paintSquare(g, xStart, yStart, mapModel.getMapSquare(pos));
495  }
496  xStart += isoMapSquareInfo.getXLen2();
497  yStart += isoMapSquareInfo.getYLen2();
498  }
499  }
500 
501  paintMapGrid(g);
503  }
504 
510  private Rectangle getRepaintRec(@NotNull final Rectangle visibleRectangle) {
511  // This Rectangle will be returned
512  final Rectangle rec = new Rectangle();
513  // Upper left corner of viewport
514  final Point posUL = visibleRectangle.getLocation();
515  // Dimension of viewport
516  final Dimension visDim = visibleRectangle.getSize();
517  // Other positions of viewport corners
518  final Point posUR = new Point(posUL.x + visDim.width, posUL.y);
519  final Point posDL = new Point(posUL.x, posUL.y + visDim.height);
520  final Point posDR = new Point(posUR.x, posDL.y);
521  // Calculate map positions of corners and from them properties of Rectangle
522  rec.x = getSquareLocationAt(posUL, tmpPoint) ? tmpPoint.x : 0;
523  rec.y = getSquareLocationAt(posUR, tmpPoint) ? tmpPoint.y : 0;
524  rec.height = getSquareLocationAt(posDL, tmpPoint) ? tmpPoint.y - rec.y + 1 : mapSize.getHeight() - rec.y;
525  rec.width = getSquareLocationAt(posDR, tmpPoint) ? tmpPoint.x - rec.x + 1 : mapSize.getWidth() - rec.x;
526  return rec;
527  }
528 
535  protected abstract boolean isGameObjectVisible(@NotNull G gameObject);
536 
545  protected void paintGameObjectIfVisible(@NotNull final Graphics2D g, final int xStart, final int yStart, @NotNull final G gameObject) {
546  final G head = gameObject.getHead();
547  if (isGameObjectVisible(head)) {
548  paintGameObject(g, xStart, yStart, gameObject, false);
549  }
550  }
551 
560  private void paintGameObject(@NotNull final Graphics2D g, final int xStart, final int yStart, @NotNull final G gameObject, final boolean inSpawnPoint) {
561  final G head = gameObject.getHead();
562  final Icon icon;
563  if ("trans.101".equals(head.getFaceObjName())) {
564  icon = unknownSquareIcon;
565  } else {
566  final boolean drawDouble = head.isDrawDouble(mapViewSettings.isDoubleFaces());
567  final boolean isStretched = head.isStretched(mapViewSettings.isTileStretching());
568  if (mapViewSettings.isAlphaType(head.getEditType())) {
569  if (drawDouble) {
570  icon = head.getTransparentDoubleImage();
571  } else {
572  icon = head.getTransparentImage();
573  }
574  } else {
575  final long stretchFactor;
576  if (isStretched && (stretchFactor = head.getStretchFactor()) != 0) {
577  icon = head.getStretchedImage(stretchFactor);
578  } else if (drawDouble) {
579  icon = head.getDoubleImage();
580  } else {
581  icon = head.getNormalImage();
582  }
583  }
584  }
585  final int xOffset = head.getAttributeInt(DefaultIsoGameObject.ALIGN);
586  final int yOffset = head.getYOffset();
587  final int zoom = head.getAttributeInt(DefaultIsoGameObject.ZOOM);
588  final double rotate = getRotate(head);
589  final int alpha = head.getAttributeInt(DefaultIsoGameObject.ALPHA);
590  final int tmpIconWidth;
591  final int tmpIconHeight;
592  if (zoom == 0 || zoom == 100) {
593  tmpIconWidth = icon.getIconWidth();
594  tmpIconHeight = icon.getIconHeight();
595  } else {
596  tmpIconWidth = (icon.getIconWidth() * zoom + 50) / 100;
597  tmpIconHeight = (icon.getIconHeight() * zoom + 50) / 100;
598  }
599  final int iconWidth;
600  final int iconHeight;
601  if (rotate < 0.001) {
602  iconWidth = tmpIconWidth;
603  iconHeight = tmpIconHeight;
604  } else {
605  iconWidth = (int) (Math.abs(Math.cos(rotate) * tmpIconWidth) + 0.5) + (int) (Math.abs(Math.sin(rotate) * tmpIconHeight) + 0.5);
606  iconHeight = (int) (Math.abs(Math.sin(rotate) * tmpIconWidth) + 0.5) + (int) (Math.abs(Math.cos(rotate) * tmpIconHeight) + 0.5);
607  }
608  if (head.getMultiRefCount() > 0) {
609  final R archetype = gameObject.getArchetype();
610  if (inSpawnPoint || archetype.isLowestPart()) {
611  final int headMultiShapeID = head.getArchetype().getMultiShapeID();
612  final int multiPartNr = archetype.getMultiPartNr();
613  final int x = xStart - multiPositionData.getXOffset(headMultiShapeID, multiPartNr) + multiPositionData.getWidth(headMultiShapeID) / 2 - iconWidth / 2;
614  final int y = yStart - multiPositionData.getYOffset(headMultiShapeID, multiPartNr) + isoMapSquareInfo.getYLen() - iconHeight;
615  paintScaledIcon(g, icon, x + xOffset, y - yOffset, zoom, alpha, rotate, tmpIconWidth, tmpIconHeight, iconWidth, iconHeight);
616  }
617  } else {
618  final int x;
619  if (iconWidth > isoMapSquareInfo.getXLen()) {
620  x = xStart + isoMapSquareInfo.getXLen2() - iconWidth / 2;
621  } else {
622  x = xStart;
623  }
624  final int y = yStart + isoMapSquareInfo.getYLen() - iconHeight;
625  paintScaledIcon(g, icon, x + xOffset, y - yOffset, zoom, alpha, rotate, tmpIconWidth, tmpIconHeight, iconWidth, iconHeight);
626  }
627 
628  // Paint first object (most likely a mob) in spawn points.
629  if (!inSpawnPoint && isSpawnPoint(head)) {
630  final G mob = head.getFirst();
631  if (mob != null) {
632  paintGameObject(g, xStart, yStart, mob, true);
633  }
634  }
635  }
636 
642  private static double getRotate(@NotNull final Attributes head) {
643  final int rotate = -head.getAttributeInt(DefaultIsoGameObject.ROTATE) % 360;
644  return (rotate < 0 ? rotate + 360 : rotate) * 2 * Math.PI / 360;
645  }
646 
661  private void paintScaledIcon(@NotNull final Graphics2D g, @NotNull final Icon icon, final int x, final int y, final int zoom, final int alpha, final double rotate, final int oldIconWidth, final int oldIconHeight, final int newIconWidth, final int newIconHeight) {
662  if (zoom <= 0 || zoom == 100) {
663  paintAlphaIcon(g, icon, x, y, alpha, rotate, oldIconWidth, oldIconHeight, newIconWidth, newIconHeight);
664  } else {
665  final AffineTransform savedTransform = g.getTransform();
666  try {
667  g.translate(x, y);
668  g.scale(zoom / 100.0, zoom / 100.0);
669  paintAlphaIcon(g, icon, 0, 0, alpha, rotate, oldIconWidth, oldIconHeight, newIconWidth, newIconHeight);
670  } finally {
671  g.setTransform(savedTransform);
672  }
673  }
674  }
675 
689  private void paintAlphaIcon(@NotNull final Graphics2D g, @NotNull final Icon icon, final int x, final int y, final int alpha, final double rotate, final int oldIconWidth, final int oldIconHeight, final int newIconWidth, final int newIconHeight) {
690  if (alpha <= 0 || alpha >= 255) {
691  paintRotatedIcon(g, icon, x, y, rotate, oldIconWidth, oldIconHeight, newIconWidth, newIconHeight);
692  } else {
693  final Composite savedComposite = g.getComposite();
694  try {
695  g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha / 255.0F));
696  paintRotatedIcon(g, icon, x, y, rotate, oldIconWidth, oldIconHeight, newIconWidth, newIconHeight);
697  } finally {
698  g.setComposite(savedComposite);
699  }
700  }
701  }
702 
715  private void paintRotatedIcon(@NotNull final Graphics2D g, @NotNull final Icon icon, final int x, final int y, final double rotate, final int oldIconWidth, final int oldIconHeight, final int newIconWidth, final int newIconHeight) {
716  if (rotate < 0.001) {
717  g.translate(x, y);
718  try {
719  paintIcon(g, icon);
720  } finally {
721  g.translate(-x, -y);
722  }
723  } else {
724  final AffineTransform savedTransform = g.getTransform();
725  try {
726  g.translate(x + newIconWidth / 2, y + newIconHeight / 2);
727  g.rotate(rotate);
728  g.translate(-oldIconWidth / 2, -oldIconHeight / 2);
729  paintIcon(g, icon);
730  } finally {
731  g.setTransform(savedTransform);
732  }
733  }
734  }
735 
741  protected void paintIcon(@NotNull final Graphics2D g, @NotNull final Icon icon) {
742  icon.paintIcon(this, g, 0, 0);
743  }
744 
750  private boolean isSpawnPoint(@NotNull final BaseObject<G, A, R, ?> gameObject) {
751  return gameObject.getTypeNo() == spawnPointTypeNo;
752  }
753 
760  private void paintMapSelection(@NotNull final Graphics g) {
761  final boolean lightVisible = isLightVisible() ^ mapViewSettings.isLightVisible();
762  final Point point = new Point();
763  for (int y = 0; y < mapSize.getHeight(); y++) {
764  int xStart = origin.x - (y + 1) * isoMapSquareInfo.getXLen2();
765  int yStart = origin.y + y * isoMapSquareInfo.getYLen2();
766  point.y = y;
767  for (int x = 0; x < mapSize.getWidth(); x++) {
768  point.x = x;
769  final int[] offsets = tileStretchingOffsets(point, foundSubLayers);
770 
771  for (int subLayer = 0; subLayer < offsets.length; subLayer++) {
772  if (!foundSubLayers[subLayer]) {
773  continue;
774  }
775  final int yStart2 = yStart + offsets[subLayer];
776  if (g.hitClip(xStart, yStart2, isoMapSquareInfo.getXLen(), isoMapSquareInfo.getYLen())) {
777  final int gridFlags = mapGrid.getFlags(x, y);
778  final boolean light = lightVisible && mapModel.getMapSquare(point).isLight();
779  gridMapSquarePainter.paint(g, gridFlags, light, xStart, yStart2, this);
780  } else {
781  /* DO NOTHING if outside clip region.
782  * DO NOT use continue. xStart and yStart are recalculated at the end of the loop.
783  */
784  }
785  }
786  xStart += isoMapSquareInfo.getXLen2();
787  yStart += isoMapSquareInfo.getYLen2();
788  }
789  }
790  }
791 
798  private void paintMapGrid(@NotNull final Graphics g) {
799  if (mapViewSettings.isGridVisible()) {
800  // draw iso grid
801  g.setColor(Color.black);
802 
803  final int mapWidth = mapSize.getWidth();
804  final int mapHeight = mapSize.getHeight();
805  for (int x = 0; x <= mapWidth; x++) {
806  g.drawLine(origin.x + x * isoMapSquareInfo.getXLen2() - 1, origin.y + x * isoMapSquareInfo.getYLen2() - 1, origin.x - (mapHeight - x) * isoMapSquareInfo.getXLen2() - 1, origin.y + (mapHeight + x) * isoMapSquareInfo.getYLen2() - 1);
807  }
808  for (int y = 0; y <= mapHeight; y++) {
809  g.drawLine(origin.x - y * isoMapSquareInfo.getXLen2() - 1, origin.y + y * isoMapSquareInfo.getYLen2() - 1, origin.x + (mapWidth - y) * isoMapSquareInfo.getXLen2() - 1, origin.y + (mapWidth + y) * isoMapSquareInfo.getYLen2() - 1);
810  }
811  }
812  }
813 
821  protected int[] tileStretchingOffsets(@NotNull final Point point, final boolean[] foundSubLayers) {
822  Arrays.fill(foundSubLayers, false);
823 
824  final int[] offsets = new int[DefaultIsoGameObject.MAX_SUB_LAYERS];
825  boolean foundAny = false;
826  if (mapViewSettings.isTileStretching()) {
827  for (final G gameObject : mapModel.getMapSquare(point)) {
828  final G head = gameObject.getHead();
829  if (head.isStretched(true) && head.getAttributeInt(DefaultIsoGameObject.LAYER) == 1) {
830  final int yOffset = head.getAttributeInt(DefaultIsoGameObject.Z);
831  final int subLayer = head.getAttributeInt(DefaultIsoGameObject.SUB_LAYER);
832  if (yOffset > offsets[subLayer]) {
833  offsets[subLayer] = yOffset;
834  }
835  foundSubLayers[subLayer] = true;
836  foundAny = true;
837  }
838  }
839  }
840 
841  if (!foundAny) {
842  foundSubLayers[0] = true;
843  }
844 
845  for (int subLayer = 0; subLayer < offsets.length; subLayer++) {
846  offsets[subLayer] = maxYOffset - offsets[subLayer];
847  }
848 
849  return offsets;
850  }
851 
852  @Override
853  public boolean getSquareLocationAt(@NotNull final Point point, @NotNull final Point retPoint) {
854  if (maxYOffset == 0 && minYOffset == 0) {
855  final int x0 = point.x - origin.x;
856  final int y0 = point.y - origin.y;
857  final int yt = (2 * y0 - x0) / 2;
858  final int xt = yt + x0;
859  final int xm = xt / isoMapSquareInfo.getXLen2();
860  final int ym = yt / isoMapSquareInfo.getYLen2() / 2;
861  if (xm < 0 || xm >= mapSize.getWidth() || ym < 0 || ym >= mapSize.getHeight()) {
862  return false;
863  }
864 
865  retPoint.setLocation(xm, ym);
866  return true;
867  }
868 
869  assert mapViewSettings.isTileStretching();
870 
871  boolean retval = false;
872  for (int y = 0; y < mapSize.getHeight(); y++) {
873  int xStart = origin.x - (y + 1) * isoMapSquareInfo.getXLen2();
874  int yStart = origin.y + y * isoMapSquareInfo.getYLen2();
875  for (int x = 0; x < mapSize.getWidth(); x++) {
876  tmpPoint.setLocation(x, y);
877  final int[] offsets = tileStretchingOffsets(tmpPoint, foundSubLayers);
878 
879  for (int subLayer = 0; subLayer < offsets.length; subLayer++) {
880  if (!foundSubLayers[subLayer]) {
881  continue;
882  }
883  final int yPos = yStart + offsets[subLayer];
884  long stretch = 0;
885 
886  for (final G gameObject : mapModel.getMapSquare(tmpPoint)) {
887  final G head = gameObject.getHead();
888  if (head.isStretched(true) && head.getAttributeInt(DefaultIsoGameObject.LAYER) == 1 && head.getAttributeInt(DefaultIsoGameObject.SUB_LAYER) == subLayer) {
889  stretch = head.getStretchFactor();
890  break;
891  }
892  }
893 
894  if (point.x >= xStart && point.x <= xStart + isoMapSquareInfo.getXLen() && point.y >= yPos && point.y <= yPos + isoMapSquareInfo.getYLen() + ((stretch >> 24) & 0xff)) {
895  if (StretchedImageFilter.coordsInTile(stretch, point.x - xStart, point.y - yPos)) {
896  retPoint.setLocation(tmpPoint);
897  retval = true;
898  }
899  }
900  }
901 
902  xStart += isoMapSquareInfo.getXLen2();
903  yStart += isoMapSquareInfo.getYLen2();
904  }
905  }
906 
907  return retval;
908  }
909 
913  private void resizeFromModel() {
914  final Point pos = new Point();
915  final int mapWidth = mapSize.getWidth();
916  final int mapHeight = mapSize.getHeight();
917  minYOffset = 0;
918  maxYOffset = 0;
919  if (mapViewSettings.isTileStretching()) {
920  for (pos.y = 0; pos.y < mapHeight; pos.y++) {
921  for (pos.x = 0; pos.x < mapWidth; pos.x++) {
922  for (final G gameObject : mapModel.getMapSquare(pos)) {
923  final G head = gameObject.getHead();
924  if (head.isStretched(true) && head.getAttributeInt(DefaultIsoGameObject.LAYER) == 1) {
925  final int yOffset = head.getAttributeInt(DefaultIsoGameObject.Z);
926 
927  if (yOffset > maxYOffset) {
928  maxYOffset = yOffset;
929  } else if (yOffset < minYOffset) {
930  minYOffset = yOffset;
931  }
932  }
933  }
934  }
935  }
936  }
937  // define how much drawing space we need for the map
938  final int sum = mapWidth + mapHeight;
939  final Dimension forcedSize = new Dimension(2 * borderOffset.x + sum * isoMapSquareInfo.getXLen2(), 2 * borderOffset.y + sum * isoMapSquareInfo.getYLen2() + maxYOffset + Math.abs(minYOffset));
940  setPreferredSize(forcedSize);
941  setMinimumSize(forcedSize);
942  revalidate();
943  }
944 
945 }
boolean isAlphaType(int v)
Returns whether the specified edit type is to be shown transparent.
int [] tileStretchingOffsets(@NotNull final Point point, final boolean[] foundSubLayers)
Calculates the tile stretching Y offset.
final MapGridListener mapGridListener
The MapGridListener to track changes in mapGrid.
AbstractIsoMapRenderer(final int spawnPointTypeNo, @NotNull final MapViewSettings mapViewSettings, @NotNull final MapModel< G, A, R > mapModel, @NotNull final MapGrid mapGrid, final int borderOffsetX, final int borderOffsetY, @NotNull final MultiPositionData multiPositionData, @NotNull final IsoMapSquareInfo isoMapSquareInfo, @NotNull final GridMapSquarePainter gridMapSquarePainter, @NotNull final GameObjectParser< G, A, R > gameObjectParser, @NotNull final Icon unknownSquareIcon)
Creates a new instance.
final MultiPositionData multiPositionData
The MultiPositionData instance to query for multi-part objects.
int getYOffset(final int shapeID, final int positionID)
Calculate the y-offset from the topmost pixel of the big face image and the default y-position (The d...
final Point origin
The origin is the point in the north-west corner.
A MapRenderer that renders isometric squares.
final Point borderOffset
The offset to map borders (32 for std.
A MapModel reflects the data of a map.
Definition: MapModel.java:75
boolean isLight()
Returns whether this map square is affected by any light emitting game objects.
Definition: MapSquare.java:389
Reading and writing of maps, handling of paths.
boolean getSquareLocationAt(@NotNull final Point point, @NotNull final Point retPoint)
void paintAlphaIcon(@NotNull final Graphics2D g, @NotNull final Icon icon, final int x, final int y, final int alpha, final double rotate, final int oldIconWidth, final int oldIconHeight, final int newIconWidth, final int newIconHeight)
Paints an icon at a given alpha value.
MapModel< G, A, R > getMapModel()
Returns the MapModel this map square is part of.
Definition: MapSquare.java:99
This package contains the framework for validating maps.
static final String ZOOM
The name of the "zoom" attribute.
static final String LAYER
The name of the "layer" attribute.
final MapModelListener< G, A, R > mapModelListener
The MapModelListener to track changes in mapModel.
static final String ALPHA
The name of the "alpha" attribute.
Interface for listeners listening on MapModel events.
final MapModel< G, A, R > mapModel
The MapModel to render.
boolean lightVisible
Whether the setting for lighted map squares is inverted.
Interface for classes that read or write GameObject instances.
int getYLen2()
Returns the vertical center of a square.
static final long serialVersionUID
The serial version UID.
int getFlags(final int x, final int y)
Returns the flags of a square.
Definition: MapGrid.java:476
void removeMapGridListener(@NotNull final MapGridListener listener)
Removes a MapGridListener.
Definition: MapGrid.java:198
boolean isLightVisible()
Get the visibility of the light.
void paintScaledIcon(@NotNull final Graphics2D g, @NotNull final Icon icon, final int x, final int y, final int zoom, final int alpha, final double rotate, final int oldIconWidth, final int oldIconHeight, final int newIconWidth, final int newIconHeight)
Paints an icon at a given zoom factor and alpha value.
int getYLen()
Returns the vertical size of a square.
void paintMapSelection(@NotNull final Graphics g)
Paints the selection for the whole map.
final int spawnPointTypeNo
The game object type number of spawn points.
Base package of all Gridarta classes.
int getWidth(final int shapeID)
Returns the total width for a multi-square image.
final MapViewSettings mapViewSettings
The MapViewSettings instance to use.
Abstract base class for classes implementing MapRenderer.
Interface for listeners listening to MapGridEvents.
boolean isGridVisible()
Get the visibility of the grid.
final IsoMapSquareInfo isoMapSquareInfo
The IsoMapSquareInfo to use.
void paintMapGrid(@NotNull final Graphics g)
Paints the grid of the whole map.
static final String SUB_LAYER
The name of the "sub_layer" attribute.
Interface for event listeners that are interested in changes on MapViewSettings.
void removeMapViewSettingsListener(@NotNull MapViewSettingsListener listener)
Unregister a MapViewSettingsListener.
Container for settings that affect the rendering of maps.
MapSquare< G, A, R > getMapSquare(@NotNull Point pos)
Get the square at a specified location.
static final String Z
The name of the "z" attribute.
GameObjects are the objects based on Archetypes found on maps.
abstract void clearBackground(@NotNull Graphics g)
Clears the window to background color if necessary.
int getWidth()
Returns the width of the area.
Definition: Size2D.java:96
void paintGameObjectIfVisible(@NotNull final Graphics2D g, final int xStart, final int yStart, @NotNull final G gameObject)
Paints a single game object if it is visible according to current editor settings.
Point getMapLocation()
Returns the coordinate on the map.
Definition: MapSquare.java:124
abstract void paintSquare(@NotNull Graphics2D g, int x, int y, @NotNull MapSquare< G, A, R > square)
Paints one square.
The MultiPositionData class stores an array of numbers which is required in order to calculate displa...
2D-Grid containing flags for selection, pre-selection, cursor, warnings and errors.
Definition: MapGrid.java:45
void paint(@NotNull final Graphics graphics, final int gridFlags, final boolean light, final int x, final int y, @NotNull final ImageObserver imageObserver)
Paints overlay images for one grid square.
static final String ROTATE
The name of the "rotate" attribute.
final Icon unknownSquareIcon
The Icon drawn into squares without game objects.
final GameObjectParser< G, A, R > gameObjectParser
The GameObjectParser for creating tooltip information or.
Provides information about isometric map squares.
void removeMapModelListener(@NotNull MapModelListener< G, A, R > listener)
Unregister a map listener.
final boolean [] foundSubLayers
Boolean array for tileStretchingOffsets to avoid allocating lots of arrays.
Rectangle getRepaintRec(@NotNull final Rectangle visibleRectangle)
Returns smallest Rectangle on the map that needs to be repaint.
abstract boolean isGameObjectVisible(@NotNull G gameObject)
Checks whether a game object is visible according to current editor settings.
void paintComponent2(@NotNull final Graphics2D g)
Paints this component.
The face is the appearance of an object.
void calculateOrigin()
Calculates the origin which is located in the NORTH_WEST-corner of the map.
boolean isLightVisible()
Returns whether the setting for lighted map squares should be inverted.
final MapViewSettingsListener mapViewSettingsListener
The MapViewSettingsListener attached to mapViewSettings.
void paintGameObject(@NotNull final Graphics2D g, final int xStart, final int yStart, @NotNull final G gameObject, final boolean inSpawnPoint)
Paints a single game object.
int getXLen2()
Returns the horizontal center of a square.
An interface for classes that collect errors.
void paintIcon(@NotNull final Graphics2D g, @NotNull final Icon icon)
Paints an icon.
An ImageFilter that produces stretched faces.
boolean isSpawnPoint(@NotNull final BaseObject< G, A, R, ?> gameObject)
Returns whether the given BaseObject is a spawn point.
int getHeight()
Returns the height of the area.
Definition: Size2D.java:104
void paintRotatedIcon(@NotNull final Graphics2D g, @NotNull final Icon icon, final int x, final int y, final double rotate, final int oldIconWidth, final int oldIconHeight, final int newIconWidth, final int newIconHeight)
Paints an icon at a given rotation angle.
void setBorderOffset(final int x, final int y)
Sets the offset to map borders (32 for std.
Default implementation for GameObject implementing classes.
static double getRotate(@NotNull final Attributes head)
Returns the rotation angle of a game object.
static final Color BACKGROUND_COLOR
The background color for created images.
static boolean coordsInTile(final long stretch, final int x, final int y)
Checks whether the specified coordinates are inside a (possibly stretched) isometric tile...
int getXOffset(final int shapeID, final int positionID)
Calculate the x-offset from the leftmost pixel of the big face image and the default x-position (The ...
boolean isTileStretching()
Returns the tile-stretching setting.
static final String ALIGN
The name of the "align" attribute.
final GridMapSquarePainter gridMapSquarePainter
The GridMapSquarePainter to use.
The location of a map file with a map directory.
Definition: MapFile.java:31
int getXLen()
Returns the horizontal size of a square.
boolean isDoubleFaces()
Get whether double faces are drawn double height.
The class Size2D represents a 2d rectangular area.
Definition: Size2D.java:30
This event is created by MapGrid.
void resizeFromModel()
Refreshes the data in the view from the model.