/******************************************************************************* * Rhythos Editor is a game editor and project management tool for making RPGs on top of the Rhythos Game system. * * Copyright (C) 2013 David Maletz * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package mrpg.editor; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Polygon; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import javax.swing.JPanel; import javax.swing.Scrollable; import mrpg.world.BasicTilemap; import mrpg.world.Direction; import mrpg.world.Tile; public class TilesetEditor extends JPanel implements MouseListener, MouseMotionListener, Scrollable { private static final long serialVersionUID = -2758279297055018804L; public static Color dirColor = new Color(255,255,255,200), dirSelColor = new Color(250,248,160,200), dirColorOutline = new Color(0,0,0,200); public static final Polygon arrow = new Polygon(new int[]{0,0,-3,2,7,4,4}, new int[]{6,2,2,-4,2,2,6}, 7); private BasicTilemap tilemap; private final Rectangle rect = new Rectangle(); private int selX, selY, edge=0, tile_size; public TilesetEditor(int ts){tile_size = ts; setPreferredSize(new Dimension(8*TilesetViewer.TILE_SIZE+1, 8*TilesetViewer.TILE_SIZE+1)); addMouseListener(this); addMouseMotionListener(this);} public void setTilemap(BasicTilemap t){ tilemap = null; Dimension d; if(t == null) d = new Dimension(8*TilesetViewer.TILE_SIZE+1, 8*TilesetViewer.TILE_SIZE+1); else {tilemap = t; d = new Dimension(t.getTilesX()*TilesetViewer.TILE_SIZE+1, t.getTilesY()*TilesetViewer.TILE_SIZE+1);} setMinimumSize(d); setPreferredSize(d); revalidate(); repaint(); } public void paint(Graphics g){ Graphics2D g2d = (Graphics2D)g; Graphics2D g2 = (Graphics2D)g.create(); double s = ((double)TilesetViewer.TILE_SIZE)/tile_size; g2.scale(s,s); g2.getClipBounds(rect); g2.clearRect(rect.x, rect.y, rect.width, rect.height); if(tilemap != null){ BufferedImage image = (BufferedImage)tilemap.getTile(0).image; int w = Math.min(rect.x+rect.width, image.getWidth())-rect.x; int h = Math.min(rect.y+rect.height, image.getHeight())-rect.y; if(w > 0 && h > 0){ g2.drawImage(image, rect.x, rect.y, rect.x+w, rect.y+h, rect.x, rect.y, rect.x+w, rect.y+h, this); g.getClipBounds(rect); int stx = (int)Math.floor(((double)(rect.x))/TilesetViewer.TILE_SIZE), sty = (int)Math.floor(((double)(rect.y))/TilesetViewer.TILE_SIZE), endx = Math.min(tilemap.getTilesX()-1, (int)Math.floor(((double)(rect.x+w*s))/TilesetViewer.TILE_SIZE)), endy = Math.min(tilemap.getTilesY()-1, (int)Math.floor(((double)(rect.y+h*s))/TilesetViewer.TILE_SIZE)); int d = 4, first = (TilesetViewer.TILE_SIZE-(5*d))/2+1; for(int y=sty; y<=endy; y++) for(int x=stx; x<=endx; x++){ int e = 0; if(selX == x && selY == y) e = edge; byte walkable = tilemap.getTile(x, y).info.getWalkable(); AffineTransform t = g2d.getTransform(); g2d.translate(x*TilesetViewer.TILE_SIZE+first+d*2-1, y*TilesetViewer.TILE_SIZE+first-1); g.setColor((Direction.up(e))?dirSelColor:dirColor); if(Direction.up(walkable)) g2d.fillPolygon(arrow); else g2d.fillRect(0, 0, d, d); g.setColor(dirColorOutline); if(Direction.up(walkable)) g2d.drawPolygon(arrow); else g2d.drawRect(0, 0, d, d); g2d.translate(d*2, d*2); g2d.rotate(Math.PI/2, 2, 2); g.setColor((Direction.right(e))?dirSelColor:dirColor); if(Direction.right(walkable)) g2d.fillPolygon(arrow); else g2d.fillRect(0, 0, d, d); g.setColor(dirColorOutline); if(Direction.right(walkable)) g2d.drawPolygon(arrow); else g2d.drawRect(0, 0, d, d); g2d.translate(d*2, d*2); g2d.rotate(Math.PI/2, 2, 2); g.setColor((Direction.down(e))?dirSelColor:dirColor); if(Direction.down(walkable)) g2d.fillPolygon(arrow); else g2d.fillRect(0, 0, d, d); g.setColor(dirColorOutline); if(Direction.down(walkable)) g2d.drawPolygon(arrow); else g2d.drawRect(0, 0, d, d); g2d.translate(d*2, d*2); g2d.rotate(Math.PI/2, 2, 2); g.setColor((Direction.left(e))?dirSelColor:dirColor); if(Direction.left(walkable)) g2d.fillPolygon(arrow); else g2d.fillRect(0, 0, d, d); g.setColor(dirColorOutline); if(Direction.left(walkable)) g2d.drawPolygon(arrow); else g2d.drawRect(0, 0, d, d); g2d.setTransform(t); } } else g.getClipBounds(rect); } else g.getClipBounds(rect); g.setColor(Color.black); Dimension dim = getPreferredSize(); int rw = Math.min(dim.width, rect.x+rect.width), rh = Math.min(dim.height, rect.y+rect.height); for(int y=(int)Math.ceil(rect.y*1.0/TilesetViewer.TILE_SIZE)*TilesetViewer.TILE_SIZE; y<rh; y+=TilesetViewer.TILE_SIZE) g.drawLine(rect.x, y, rw-1, y); for(int x=(int)Math.ceil(rect.x*1.0/TilesetViewer.TILE_SIZE)*TilesetViewer.TILE_SIZE; x<rw; x+=TilesetViewer.TILE_SIZE) g.drawLine(x, rect.y, x, rh-1); } public int getScrollableUnitIncrement(Rectangle r, int o, int d){return TilesetViewer.TILE_SIZE;} public int getScrollableBlockIncrement(Rectangle r, int o, int d){return TilesetViewer.TILE_SIZE;} public Dimension getPreferredScrollableViewportSize(){return getPreferredSize();} public boolean getScrollableTracksViewportWidth(){return false;} public boolean getScrollableTracksViewportHeight(){return false;} public void mouseDragged(MouseEvent e) {} public void mouseMoved(MouseEvent e) { int x = e.getX()/TilesetViewer.TILE_SIZE, y = e.getY()/TilesetViewer.TILE_SIZE, dx = e.getX()-x*TilesetViewer.TILE_SIZE, dy = e.getY()-y*TilesetViewer.TILE_SIZE; int d = 4, first = (TilesetViewer.TILE_SIZE-(5*d))/2+1; boolean inxc = dx >= first+d && dx <= first+d*3, inyc = dy >= first+d && dy <= first+d*3; int ed = 0; if(inxc && dy < first+d) ed = Direction.UP; if(inxc && dy > first+3*d) ed = Direction.DOWN; if(inyc && dx < first+d) ed = Direction.LEFT; if(inyc && dx > first+3*d) ed = Direction.RIGHT; if(inxc && inyc) ed = Direction.LINEAR; if(x != selX || y != selY || ed != edge){repaint(selX*TilesetViewer.TILE_SIZE,selY*TilesetViewer.TILE_SIZE,TilesetViewer.TILE_SIZE,TilesetViewer.TILE_SIZE); selX = x; selY = y; edge = ed; repaint(selX*TilesetViewer.TILE_SIZE,selY*TilesetViewer.TILE_SIZE,TilesetViewer.TILE_SIZE,TilesetViewer.TILE_SIZE);} } public void mouseClicked(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) { if(tilemap == null) return; if(selX >= 0 && selX < tilemap.getTilesX() && selY >= 0 && selY < tilemap.getTilesY() && edge != 0){ Tile.Info info = tilemap.getTile(selX, selY).info; info.setWalkable((byte)(info.getWalkable() ^ edge)); repaint(selX*TilesetViewer.TILE_SIZE,selY*TilesetViewer.TILE_SIZE,TilesetViewer.TILE_SIZE,TilesetViewer.TILE_SIZE); } } public void mouseReleased(MouseEvent e) {} }