Generate texture atlas from multitude of textures

hello guys, I’d like to make a dynamic atlas from textures, is there something in JMonkey I can use or I’ll have to handle it all by myself?

thxxx

This is the code I have used long time ago to create texture atlas for tga->png icons. Not really complicated, but might get you bootstrapped if you will have to write something on your own

[java]
public static void main(String[] args) throws Exception {
BufferedImage firstImage = TargaReader.getImage(args[0]);

	int width = firstImage.getWidth();
	int height = firstImage.getHeight();
	
	int count = args.length;
	
	System.out.println("Will try to stitch " + count + " images of size " + width + " x " + height);
	if ( width != height ) {
		System.out.println("Width has to be same as height");
	}
	
	int side = (int) Math.ceil(Math.sqrt(count));
	
	System.out.println("Resulting image will be square with side of " + side + " cells for total size of " + width*side + " pixels");
	
	BufferedImage result = new BufferedImage(width*side,width*side,firstImage.getType());
	Graphics2D g = (Graphics2D) result.getGraphics();
	
	for ( int i =0; i < count; i++ ) {
		BufferedImage img = TargaReader.getImage(args[i]);
		if ( img.getWidth() != width || img.getHeight() != height ) {
			throw new IllegalArgumentException("Wrongly sized image at " + args[i]);
		}
		int x = width* (i%side);
		int y = height * (i/side);
		g.drawImage(img,x,y,width,height,null);
	}
	File out = new File("out.png");
	System.out.println("Writing image to " + out.getAbsolutePath());
	ImageIO.write(result, "png", out);
	
}

[/java]

Regarding ‘dynamic’ part, you could just pass BufferedImage further to application instead of writing it to disk and convert into jme3 image with AWTLoader.

1 Like
@abies said: This is the code I have used long time ago to create texture atlas for tga->png icons. Not really complicated, but might get you bootstrapped if you will have to write something on your own

[java]
public static void main(String args) throws Exception {
BufferedImage firstImage = TargaReader.getImage(args[0]);

	int width = firstImage.getWidth();
	int height = firstImage.getHeight();
	
	int count = args.length;
	
	System.out.println("Will try to stitch " + count + " images of size " + width + " x " + height);
	if ( width != height ) {
		System.out.println("Width has to be same as height");
	}
	
	int side = (int) Math.ceil(Math.sqrt(count));
	
	System.out.println("Resulting image will be square with side of " + side + " cells for total size of " + width*side + " pixels");
	
	BufferedImage result = new BufferedImage(width*side,width*side,firstImage.getType());
	Graphics2D g = (Graphics2D) result.getGraphics();
	
	for ( int i =0; i < count; i++ ) {
		BufferedImage img = TargaReader.getImage(args[i]);
		if ( img.getWidth() != width || img.getHeight() != height ) {
			throw new IllegalArgumentException("Wrongly sized image at " + args[i]);
		}
		int x = width* (i%side);
		int y = height * (i/side);
		g.drawImage(img,x,y,width,height,null);
	}
	File out = new File("out.png");
	System.out.println("Writing image to " + out.getAbsolutePath());
	ImageIO.write(result, "png", out);
	
}

[/java]

Regarding ‘dynamic’ part, you could just pass BufferedImage further to application instead of writing it to disk and convert into jme3 image with AWTLoader.

wow! thx alot! :slight_smile: wasnt expecting some code ^^
thats some great stuff :slight_smile:

yeah well actually, i’ll write to disk, because I need the players to keep the generated atlas on their computer, so next time they wont have to regenerate the map :).
and also, so they can share the atlas with other players using peer to peer :smiley:

this is exactly what I was looking for thx m8 :slight_smile:

You might want to output atlas dictionary in the process of generation as well, so you can later look up coordinates by original file names if needed. And please note that above code works only for same-size inputs. Varied size inputs represent knapsack problem if you want to do them well and it was not required for me.

You might also hit a problem if your images don’t have neutral background around them, due to mipmapping bleeding colors from neighbour images.

allright thx for the tip!
for my atlas all images have a size of 128x128, and as for the bleeding, I have added padding when I map my vertices on the atlas.

but I don’t think I need an atlas dictionary,; because i’m generating a terrain atlas, and each player will have his own terrain, with some textures applied, example : one terrain might only use Ice and snow, and others would use grass and mud, so depending on what theplayer uses for generating his terrain, I save an atlas on his computer with the textures he used, then I would save a heightmap and a map containing the type of the tiles <- I think this is my dictionnary, i’ll use it later with heightmap for the path finding.

Check the TextureAtlas class in jME and the test and documentation for it.

2 Likes
@normen said: Check the TextureAtlas class in jME and the test and documentation for it.
oh thats even better :D