TextureFiller

Hi, at the moment I’m making a 2d game where I load maps from image files. If someone wanted to save space, this is a good utility for making cool maps with tiny images. What you do is make a simple image (it can be huge though eg 10000x10000) of only a few seperate colours. And then you map each colour to a small seamless texture, and then when you load the map in game, it goes through the huge image and converts the simple colours into the image you mapped each colour too. The huge 10000x10000 image will be really small because it only contains a few plain colours (so like 50kb instead of megabytes), and the seamless textures can be 128x128 or 256x256 or whatever, so they will be small too.

Even though I decided not to take this approach, I don’t have photoshop, and it makes it easy to map textures onto plain images.

This code isn’t very optimised, but it is fast enough to do the job (eg, takes 1 second to map textures to an average sized image)
If you want to you can optimise it and post a new version here :slight_smile:

Instructions:

  1. Click on the menu and click “load image”. Choose an image of your choice that has plain colours
  2. Go to the menu and click add colour->texture.
    type in the R,G,B value of the colour and press ok, then select the seamless texture you want to map to that colour.
  3. the colour that you chose on your image will now be flood filled with the texture you chose.
  4. you can save the image as a .png in the menu :slight_smile:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;


public class Main implements ActionListener
{
	private Map<Color,BufferedImage> m_mapColourToImage;
	private BufferedImage m_image;
	private JFrame m_frame;
	private DrawingSurface surface;
	private static final int width = 800;
	private static final int height = 600;
	public static void main(String[] args)
	{
		new Main();
	}
	
	private Main()
	{
		m_mapColourToImage = new HashMap<Color, BufferedImage>();
		
		m_frame = new JFrame("TextureFiller");
		m_frame.setSize(width,height);
		
		
		surface = new DrawingSurface();
		surface.setVisible(true);
		surface.setOpaque(true);
		surface.setSize(width, height);
		m_frame.add(surface);
		
		
		
		JMenuBar menuBar;
		menuBar = new JMenuBar();
		AddMenu(menuBar, "Menu","Menu","Load image","Add colour->texture", "Save image");
		m_frame.setJMenuBar(menuBar);
		
		
		m_frame.setVisible(true);
		m_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		
		
		while(true)
		{
			m_frame.repaint();
		}
	}
	
	private void AddMenu(JMenuBar menuBar, String name, String tooltip, String... menuItems)
	{
		JMenu menu = new JMenu(name);
		menu.setToolTipText(tooltip);
		
		for (String item: menuItems)
		{
			JMenuItem menuItem = new JMenuItem(item);
			menuItem.addActionListener(this);
			menu.add(menuItem);
		}
		menuBar.add(menu);
	}
	
	private class DrawingSurface extends JComponent
	{
		private static final long serialVersionUID = 1L;
		
		public void paintComponent(Graphics g) 
		{
            super.paintComponent(g);
            if (m_image != null)
            	g.drawImage(m_image, 0, 0, m_frame.getWidth(), m_frame.getHeight()-50, null);
         }
	}
	
	private BufferedImage LoadImage()
	{
		BufferedImage bi = null;
		JFileChooser fc = new JFileChooser(".");

		fc.setFileFilter(new FileFilter()
		{
			@Override
			public String getDescription()
			{
				return "image file";
			}
			
			@Override
			public boolean accept(File file)
			{
				return true;
			}
		});
		
		fc.showOpenDialog(m_frame);
			
        

        if (fc.getSelectedFile() != null)
        {
            File file = fc.getSelectedFile();
            if (file == null)
        	{
        		return null;
        	}
            
        	try
        	{
        		Image img = ImageIO.read(file);
        		
        		bi = new BufferedImage(img.getWidth(null),img.getHeight(null),BufferedImage.TYPE_INT_ARGB);
        		bi.getGraphics().drawImage(img, 0,0,bi.getWidth(),bi.getHeight(),null);
        	}
        	catch(Exception ex)
        	{
        		JOptionPane.showMessageDialog(m_frame, "Load failed: " + ex.getMessage());
        	}
        }  
        return bi;
	}
	
	private void TextureImage()
	{
		if (m_image == null)
			return;
		long time = System.currentTimeMillis();

		for (int x = 0; x < m_image.getWidth(); x++)
		{
			for (int y = 0; y < m_image.getHeight(); y++)
			{
				int rgb = m_image.getRGB(x, y);
				if (rgb != 0)
				{
					Color pixelColour = new Color(rgb);
					
					BufferedImage image = m_mapColourToImage.get(pixelColour);
					if (image != null)
					{
						m_image.setRGB(x, y, image.getRGB(x%image.getWidth(), y%image.getHeight()));
					}
				}
			}
		}
		System.out.println("Texturing took " + (float)(System.currentTimeMillis()-time)/1000 + "s");
	}

	@Override
	public void actionPerformed(ActionEvent e)
	{
		if (e.getActionCommand() == "Load image")
		{
			m_image = LoadImage();
		}
		else if (e.getActionCommand() == "Add colour->texture")
		{
			AddColour();
		}
		else if (e.getActionCommand() == "Save image")
		{
			SaveImage();
		}
	}

	private void SaveImage()
	{
		if (m_image == null)
		{
			JOptionPane.showMessageDialog(m_frame, "Please load an image first!");
			return;
		}
		
		JFileChooser fc = new JFileChooser(".");

		
		fc.setFileFilter(new FileFilter()
		{
			@Override
			public String getDescription()
			{
				return "image file";
			}
			
			@Override
			public boolean accept(File file)
			{
				return true;
			}
		});
		
		fc.showSaveDialog(m_frame);
			
        if (fc.getSelectedFile() != null)
        {
            File file = fc.getSelectedFile();
            if (file == null)
        	{
        		return;
        	}
            String filename = file.getName();
            if (filename == null)
            	return;
            
            if (!filename.toLowerCase().endsWith(".png"))
            	filename += ".png";
            
        	try
        	{
        		ImageIO.write(m_image, "PNG", new File(filename));
        	}
        	catch(Exception ex)
        	{
        		JOptionPane.showMessageDialog(m_frame, "Load failed: " + ex.getMessage());
        	}

        }
	}

	private void AddColour()
	{
		if (m_image == null)
		{
			JOptionPane.showMessageDialog(m_frame, "Please load an image first!");
			return;
		}
		String col = JOptionPane.showInputDialog("Enter colour (R,G,B) example: 255,255,255 for white");
		
		int[] colour = new int[3];
		for (int i = 0; i < 3; i++)
		{
			int index = 0;
			if (i < 2)
				index = col.indexOf(",");
			else 
				index = col.length();
			
			if (index == -1)
			{
				JOptionPane.showMessageDialog(m_frame, "R,G,B format please");
				return;
			}
			
			String s = col.substring(0,index);
			colour[i] = Integer.parseInt(s);
			if (i < 2)
				col = col.substring(index+1);
		}
		
		BufferedImage image = LoadImage();
		if (image != null)
		{
			m_mapColourToImage.put(new Color(colour[0],colour[1],colour[2]), image);
		}
		
		
		TextureImage();
	}
}