package teamcomm.gui.drawings;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
/**
* Singleton class managing the loading of textures from image files.
*
* @author Felix Thielke
*/
public class TextureLoader {
private static final TextureLoader instance = new TextureLoader();
private final Map<GL, Map<String, Texture>> textures = new HashMap<>();
/**
* Class for storing info about a texture.
*/
public static class Texture {
/**
* OpenGL texture id of the texture.
*/
public final int id;
/**
* Flag indicating whether the texture has an alpha channel.
*/
public final boolean hasAlpha;
/**
* Width of the texture in pixels.
*/
public final int width;
/**
* Height of the texture in pixels.
*/
public final int heigth;
/**
* Constructor.
*
* @param id OpenGL texture id of the texture
* @param hasAlpha flag indicating whether the texture has an alpha
* channel
* @param width width of the texture in pixels
* @param height height of the texture in pixels
*/
public Texture(final int id, final boolean hasAlpha, final int width, final int height) {
this.id = id;
this.hasAlpha = hasAlpha;
this.width = width;
this.heigth = height;
}
}
private TextureLoader() {
}
/**
* Returns the only instance of the TextureLoader.
*
* @return instance
*/
public static TextureLoader getInstance() {
return instance;
}
/**
* Loads a texture from the given file to the given OpenGL context.
*
* @param gl GL context
* @param filename path of the image file
* @return texture info
* @throws IOException if the file could not be read as an image
*/
public Texture loadTexture(final GL gl, final File filename) throws IOException {
// Get the map for the given gl context
Map<String, Texture> map = textures.get(gl);
if (map == null) {
map = new HashMap<>();
textures.put(gl, map);
}
// Check if the texture has already been loaded
Texture tex = map.get(filename.getAbsolutePath());
if (tex != null) {
return tex;
}
// Load the image
final BufferedImage img = ImageIO.read(filename);
final int[] imageData = img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth());
final boolean hasAlpha = img.getColorModel().hasAlpha();
final ByteBuffer buffer = ByteBuffer.allocate(imageData.length * (hasAlpha ? 4 : 3));
buffer.order(ByteOrder.LITTLE_ENDIAN);
for (final int c : imageData) {
if (hasAlpha) {
buffer.putInt(c);
} else {
buffer.put((byte) (c & 0xFF));
buffer.put((byte) ((c >> 8) & 0xFF));
buffer.put((byte) ((c >> 16) & 0xFF));
}
}
buffer.rewind();
// Allocate texture
final IntBuffer texIds = IntBuffer.allocate(1);
gl.glGenTextures(1, texIds);
final int textureId = texIds.get(0);
// Load texture into GL
gl.glBindTexture(GL.GL_TEXTURE_2D, textureId);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, hasAlpha ? 4 : 3, img.getWidth(), img.getHeight(), 0, hasAlpha ? GL.GL_BGRA : GL2.GL_BGR, GL.GL_UNSIGNED_BYTE, buffer);
gl.glBindTexture(GL.GL_TEXTURE_2D, 0);
tex = new Texture(textureId, hasAlpha, img.getWidth(), img.getHeight());
map.put(filename.getAbsolutePath(), tex);
return tex;
}
}