Hi guys,
I just wanted to share my sprite sheet class that I have been working on in the hopes that it will help someone else. In essence, it loads an image, crops out each tile into a separate BufferedImage and finally creates a new texture from each sub image. The id of each “tile” is stored in a 1D array of texture and begins from the first tile and continues to the end of the sheet.
I designed this with RGBA images in mind to support transparency, but it should not be too hard to adapt this to other file formats.
package goldenkey.engine;
import static org.lwjgl.opengl.GL11.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
import org.lwjgl.BufferUtils;
public class SpriteSheet
{
private Texture[] textures;
private BufferedImage sheet;
private int width, height;
private int tileSize;
private int rows;
private int cols;
public SpriteSheet(String pathToFile, int tileSize)
{
FileInputStream fis;
this.tileSize = tileSize;
// Open the file and read in the spritesheet
try
{
fis = new FileInputStream(new File(pathToFile));
sheet = ImageIO.read(fis);
width = sheet.getWidth();
height = sheet.getHeight();
rows = height / tileSize;
cols = width / tileSize;
textures = new Texture[rows * cols];
fis.close();
}
catch (IOException e)
{
System.out.println(e.getMessage());
System.exit(1);
}
// Crop out each sub image and create a texture from it
crop();
}
private void crop()
{
for(int i=0; i<rows; i++)
{
for(int j=0; j<cols; j++)
{
BufferedImage temp = sheet.getSubimage(j*tileSize, i*tileSize, tileSize, tileSize);
int id = generateTexture(temp);
textures[i * cols + j] = new Texture(id,tileSize,tileSize);
}
}
}
private int generateTexture(BufferedImage image)
{
int[] pixels = image.getRGB(0, 0, tileSize, tileSize, null, 0, tileSize);
ByteBuffer bb = BufferUtils.createByteBuffer((tileSize * tileSize) * 4);
int id = glGenTextures();
for(int i=0; i<pixels.length; i++)
{
byte r = (byte) ((pixels[i] >> 16) & 0xFF);
byte g = (byte) ((pixels[i] >> 8) & 0xFF);
byte b = (byte) ((pixels[i]) & 0xFF);
byte a = (byte) ((pixels[i] >> 24) & 0xFF);
bb.put(r);
bb.put(g);
bb.put(b);
bb.put(a);
}
bb.flip();
glBindTexture(GL_TEXTURE_2D, id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tileSize, tileSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, bb);
glBindTexture(GL_TEXTURE_2D, 0);
return id;
}
public Texture getTexture(int id)
{
if(id < 0 || id >= textures.length) return null;
return textures[id];
}
public Texture[] getAll()
{
return textures;
}
}
The Texture class is simply a wrapper class containing three fields: an int containing the texture id and a texture width and height.
I’m posting in the hopes that this will help someone else out there.