OK, this may not be the best way to distribute source code, but here it is. Each spoiler is a java class (yes, there are only 4). I developed this in Eclipse. To get it to run in Eclipse (without compiling to a jar first) you have to have your data in the DFPaint project folder in your Eclipse workspace. If you're using a different IDE, I don't know where it should go but it has to find the data folder in the default directory.
The code has approximately zero documentation, so it's pretty much up to you to figure out what I did. I haven't looked at it for a good 2 months, but I can try to answer any questions you have.
Good luck!
import java.awt.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class DFPaintTileset {
private static DFPaintTileset TILESET;
private ImageIcon tiles;
private static int tileWidth, tileHeight;
private DFPaintTileset(ImageIcon i){
tiles=i;
tileWidth = tiles.getIconWidth()/16;
tileHeight = tiles.getIconHeight()/16;
}
public static int getTileWidth(){
return tileWidth;
}
public static int getTileHeight(){
return tileHeight;
}
public static ImageIcon getImage(){
return TILESET.tiles;
}
public static void setTileset(ImageIcon i){
TILESET = new DFPaintTileset(i);
}
public static void chooseTileset(DFPaintMainWindow main){
JFileChooser file = new JFileChooser();
int f = file.showOpenDialog(main);
if(f == JFileChooser.APPROVE_OPTION) {
TILESET = new DFPaintTileset(new ImageIcon(Toolkit.getDefaultToolkit().getImage(main.getClass().getResource(file.getSelectedFile().getAbsolutePath()))));
}
}
}
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
public class DFPaintTile extends JPanel{
int tile;
ImageIcon tileset;
Image image;
int x, y, fore, back, bri;
int[] colors = {0,0,0,0,0,128,0,128,0,0,128,128,128,0,0,128,0,128,128,128,0,192,192,192,
128,128,128,0,0,255,0,255,0,0,255,255,255,0,0,255,0,255,255,255,0,255,255,255};
public DFPaintTile(int tile, int foreground, int background, boolean bright){
this.tileset=DFPaintTileset.getImage();
this.setSize(new Dimension(DFPaintTileset.getTileWidth(), DFPaintTileset.getTileHeight()));
setVisible(true);
setTile(tile, foreground, background, bright);
}
public DFPaintTile(DFPaintTile tile){
this.tileset = DFPaintTileset.getImage();
this.setSize(new Dimension(DFPaintTileset.getTileWidth(), DFPaintTileset.getTileHeight()));
setVisible(true);
setTile(tile);
}
private void init(){
int[] pixels = new int[DFPaintTileset.getTileWidth()*DFPaintTileset.getTileHeight()];
PixelGrabber tileFetcher = new PixelGrabber(tileset.getImage(), x*DFPaintTileset.getTileWidth(),
y*DFPaintTileset.getTileHeight(),DFPaintTileset.getTileWidth(),
DFPaintTileset.getTileHeight(),pixels,0, DFPaintTileset.getTileWidth());
try {
tileFetcher.grabPixels();
} catch (InterruptedException e) {
e.printStackTrace();
}
if ((tileFetcher.getStatus () & ImageObserver.ABORT) != 0) {
System.err.println ("Image fetch abort or error occurred");
return;
}
for (int i = 0; i<pixels.length; i++){
int pix = pixels[i];
int alpha = (pix >> 24) & 0xff;
int red = (pix >> 16) & 0xff;
int green = (pix >> 8) & 0xff;
int blue = (pix ) & 0xff;
int newRed, newGreen, newBlue;
if(red==255 && green==0 && blue==255){
newRed = colors[back*3];
newGreen = colors[back*3+1];
newBlue = colors[back*3+2];
}else{
newRed = colors[fore*3 +bri*24]*red/256;
newGreen = colors[fore*3+bri*24+1]*green/256;
newBlue = colors[fore*3+bri*24+2]*blue/256;
}
newRed = newRed & 0xff;
newGreen = newGreen & 0xff;
newBlue = newBlue & 0xff;
pixels[i] = (alpha<<24)|(newRed<<16)|(newGreen<<8)|newBlue;
}
image = createImage(new MemoryImageSource(DFPaintTileset.getTileWidth(), DFPaintTileset.getTileHeight(), pixels, 0, DFPaintTileset.getTileWidth()));
}
public void setTile(int tile, int fore, int back, boolean bright){
if(DFPaintMainWindow.gBox != null && DFPaintMainWindow.gBox.isSelected()){
boolean isRandom=false;
int[] ground = {39, 44, 46, 96};
for (int i = 0; i<ground.length; i++){
if (tile == ground[i] && !isRandom){
double rand = Math.random();
if(rand < 0.25)
tile = ground[0];
else if (rand<0.5)
tile = ground[1];
else if (rand<0.75)
tile = ground[2];
else
tile = ground[3];
}
}
}
this.tile=tile;
x = tile%16;
y = tile/16;
this.fore=fore%8; this.back=back%8;
if(bright) bri=1; else bri=0;
init();
repaint();
}
public void setTile(DFPaintTile t){
tile = t.tile;
fore = t.fore;
back = t.back;
bri = t.bri;
image = t.image;
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(image,0,0,this);
}
}
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.LayoutManager;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class DFPaintPanel extends JPanel{
static int tile=0;
static int fore=0;
static int back=0;
static boolean bri=false;
int gridWidth,gridHeight;
DFPaintTile[] tiles = new DFPaintTile[1];
public DFPaintPanel(int width, int height){
gridWidth = width;
gridHeight = height;
setLayout(null);
this.setLayout(new LayoutManager(){
public void addLayoutComponent(String arg0, Component arg1) {
// TODO Auto-generated method stub
}
public void layoutContainer(Container arg0) {
// TODO Auto-generated method stub
}
public Dimension minimumLayoutSize(Container arg0) {
// TODO Auto-generated method stub
return new Dimension(gridWidth*DFPaintTileset.getTileWidth(), gridHeight*DFPaintTileset.getTileHeight());
}
public Dimension preferredLayoutSize(Container arg0) {
// TODO Auto-generated method stub
return new Dimension(gridWidth*DFPaintTileset.getTileWidth(), gridHeight*DFPaintTileset.getTileHeight());
}
public void removeLayoutComponent(Component arg0) {
// TODO Auto-generated method stub
}
});
setSize(DFPaintTileset.getTileWidth()*width, DFPaintTileset.getTileHeight()*height);
setMinimumSize(new Dimension(DFPaintTileset.getTileWidth()*width, DFPaintTileset.getTileHeight()*height));
setMaximumSize(new Dimension(DFPaintTileset.getTileWidth()*width, DFPaintTileset.getTileHeight()*height));
setVisible(true);
tiles = new DFPaintTile[width*height];
addMouseMotionListener(new MouseMotionListener(){
public void mouseDragged(MouseEvent e) {
int x = e.getX();
int y = e.getY();
int gridX = x/DFPaintTileset.getTileWidth();
int gridY = y/DFPaintTileset.getTileHeight();
int index = gridY*gridWidth+gridX;
if(!e.isShiftDown())
tiles[index].setTile(tile, fore, back, bri);
else
setTile(tiles[index].tile, tiles[index].fore, tiles[index].back, tiles[index].bri==1);
}
public void mouseMoved(MouseEvent e) {}
});
addMouseListener(new MouseListener(){
public void mouseClicked(MouseEvent e) {
int gridX = e.getX()/DFPaintTileset.getTileWidth();
int gridY = e.getY()/DFPaintTileset.getTileHeight();
int index = gridY*gridWidth+gridX;
if(!e.isShiftDown())
tiles[index].setTile(tile, fore, back, bri);
else
setTile(tiles[index].tile, tiles[index].fore, tiles[index].back, tiles[index].bri==1);
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
});
DFPaintTile fill = new DFPaintTile(tile,fore,back,bri);
for (int i = 0; i<tiles.length; i++){
int x = i%gridWidth;
int y = i/gridWidth;
DFPaintTile temp = new DFPaintTile(fill);
tiles[i] = temp;
add(temp);
temp.setLocation(x*DFPaintTileset.getTileWidth(), y*DFPaintTileset.getTileHeight());
}
}
public static void setTile(int tile, int fore, int back, boolean bright){
DFPaintPanel.tile=tile;
DFPaintPanel.fore=fore%8;
DFPaintPanel.back=back%8;
bri = bright;
DFPaintMainWindow.setPreview();
}
}
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class DFPaintMainWindow extends JFrame{
public static DFPaintTile preview;
static JFrame paletteFrame;
DFPaintTile[] palette = new DFPaintTile[256];
static JSlider fSlider, bSlider;
static JCheckBox bBox, gBox;
public DFPaintMainWindow(){
try {
UIManager.setLookAndFeel(
"javax.swing.plaf.metal.MetalLookAndFeel");
} catch (Exception e) { e.printStackTrace(); }
//JFrame.setDefaultLookAndFeelDecorated(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try {
DFPaintTileset.setTileset(new ImageIcon(ImageIO.read(new File("data/art/curses_640x300.bmp"))));
} catch (IOException e) {
e.printStackTrace();
}
DFPaintPanel.back = 0;
DFPaintPanel.fore = 0;
DFPaintPanel.tile = 0;
DFPaintPanel.bri = false;
DFPaintPanel p = new DFPaintPanel(150,150);
JScrollPane scroll = new JScrollPane(p);
setContentPane(scroll);
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
setBounds(300,300, 800, 600);
setResizable(false);
p.repaint();
p.validate();
spawnPallete();
setPreview();
setVisible(true);
}
private void spawnPallete(){
int width = 16*DFPaintTileset.getTileWidth();
paletteFrame = new JFrame();
paletteFrame.setLayout(null);
fSlider = new JSlider(JSlider.HORIZONTAL, 0,7,0);
fSlider.setSnapToTicks(true);
fSlider.setPaintTicks(true);
fSlider.setMajorTickSpacing(1);
fSlider.addChangeListener(new ChangeListener(){
public void stateChanged(ChangeEvent arg0) {
DFPaintPanel.fore = ((JSlider)(arg0.getSource())).getValue();
setPreview();
}
});
fSlider.setBounds(0, 0, width, fSlider.getMinimumSize().height);
paletteFrame.add(fSlider);
bSlider = new JSlider(JSlider.HORIZONTAL, 0,7,0);
bSlider.setSnapToTicks(true);
bSlider.setMajorTickSpacing(1);
bSlider.setPaintTicks(true);
bSlider.addChangeListener(new ChangeListener(){
public void stateChanged(ChangeEvent arg0) {
DFPaintPanel.back = ((JSlider)(arg0.getSource())).getValue();
setPreview();
}
});
bSlider.setBounds(0,fSlider.getY()+fSlider.getHeight(),width, bSlider.getMinimumSize().height);
paletteFrame.add(bSlider);
bBox = new JCheckBox();
bBox.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent arg0) {
if (arg0.getStateChange() == ItemEvent.DESELECTED)
DFPaintPanel.bri = false;
else if (arg0.getStateChange() == ItemEvent.SELECTED)
DFPaintPanel.bri = true;
setPreview();
}
});
bBox.setBounds (0,bSlider.getY()+bSlider.getHeight(),bBox.getMinimumSize().width, bBox.getMinimumSize().height);
paletteFrame.add(bBox);
gBox = new JCheckBox("Vary?");
gBox.setBounds(bBox.getX()+bBox.getHeight()+DFPaintTileset.getTileWidth(), bBox.getY(), gBox.getMinimumSize().width, gBox.getMinimumSize().height);
paletteFrame.add(gBox);
for(int i = 0; i<256; i++){
palette[i] = new DFPaintTile(i, 7, 0, true);
int x = i%16;
int y = i/16;
palette[i].setLocation(x*DFPaintTileset.getTileWidth(), bBox.getY()+bBox.getHeight()+y*DFPaintTileset.getTileHeight());
paletteFrame.add(palette[i]);
palette[i].addMouseListener(new MouseListener(){
public void mouseClicked(MouseEvent arg0) {
DFPaintPanel.tile = ((DFPaintTile)arg0.getSource()).tile;
setPreview();
}
public void mouseEntered(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {}
public void mousePressed(MouseEvent arg0) {}
public void mouseReleased(MouseEvent arg0) {}
});
}
paletteFrame.setBounds(160,300, width+20, palette[255].getY()+DFPaintTileset.getTileHeight()+50);
paletteFrame.setResizable(true);
paletteFrame.setVisible(true);
}
public static void setPreview(){
if(preview != null) paletteFrame.remove(preview);
preview = new DFPaintTile(DFPaintPanel.tile, DFPaintPanel.fore, DFPaintPanel.back, DFPaintPanel.bri);
preview.setLocation(bBox.getWidth(),bBox.getY());
paletteFrame.add(preview);
paletteFrame.repaint();
paletteFrame.validate();
fSlider.setValue(DFPaintPanel.fore);
bSlider.setValue(DFPaintPanel.back);
bBox.setSelected(DFPaintPanel.bri);
}
public static void main(String[] args){
new DFPaintMainWindow();
}
}