package sprites.base;
import sprites.Texture;
import sprites.util.SpritesUtility;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import javax.media.opengl.GL4;
import javax.media.opengl.GL4;
import com.jogamp.opengl.util.texture.TextureIO;
public class SpritesTextureDatabase {
private ColorModel glAlphaColorModel, glColorModel;
private IntBuffer textureIDBuffer = IntBuffer.allocate(1);
private Map<String, Texture> textureMap;
public SpritesTextureDatabase(){
this.glAlphaColorModel = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] { 8, 8,
8, 8 }, true, false, ComponentColorModel.TRANSLUCENT,
DataBuffer.TYPE_BYTE);
this.glColorModel = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] { 8, 8,
8, 0 }, false, false, ComponentColorModel.OPAQUE,
DataBuffer.TYPE_BYTE);
this.textureMap = new HashMap<String, Texture>(16);
}
public Texture loadTexture(String resourcePath, GL4 gl) {
if(this.textureMap.containsKey(resourcePath)){
return this.textureMap.get(resourcePath);
}
Texture tex;
try {
tex = createTexture(resourcePath, gl);
return tex;
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
return null;
}
private int generateNewTextureID(GL4 gl){
gl.glGenTextures(1, textureIDBuffer);
return this.textureIDBuffer.get(0);
}
private Texture createTexture(String resourcePath, GL4 gl) throws IOException{
int srcPixelFormat;
int target = GL4.GL_TEXTURE_2D;
int dstPixelFormat = GL4.GL_RGBA;
int filter = GL4.GL_NEAREST;
// create the texture ID for this texture
int textureID = generateNewTextureID(gl);
System.out.println("New Texture ID: " + textureID);
// bind this texture
gl.glBindTexture(target, textureID);
BufferedImage bufferedImage = SpritesUtility.loadImage(resourcePath);
int originalW = bufferedImage.getWidth();
int originalH = bufferedImage.getHeight();
int texWidth = get2Fold(bufferedImage.getWidth());
int texHeight = get2Fold(bufferedImage.getHeight());
if (bufferedImage.getColorModel().hasAlpha()) {
srcPixelFormat = GL4.GL_RGBA;
} else {
srcPixelFormat = GL4.GL_RGB;
}
// convert that image into a byte buffer of texture data
ByteBuffer textureBuffer = convertImageData(bufferedImage);
if (target == GL4.GL_TEXTURE_2D) {
gl.glTexParameteri(target, GL4.GL_TEXTURE_MIN_FILTER, filter);
gl.glTexParameteri(target, GL4.GL_TEXTURE_MAG_FILTER, filter);
}
// produce a texture from the byte buffer
gl.glTexImage2D(target, 0, dstPixelFormat,
get2Fold(bufferedImage.getWidth()),
get2Fold(bufferedImage.getHeight()), 0, srcPixelFormat,
GL4.GL_UNSIGNED_BYTE, textureBuffer);
return new Texture(textureID, texWidth, texHeight, originalW, originalH);
}
/**
* Get the closest greater power of 2 to the fold number
*
* @param fold
* The target number
* @return The power of 2
*/
private static int get2Fold(int fold) {
int ret = 2;
while (ret < fold) {
ret *= 2;
}
return ret;
}
/**
* Convert the buffered image to a texture
*
* @param bufferedImage
* The image to convert to a texture
* @param texture
* The texture to store the data into
* @return A buffer containing the data
*/
private ByteBuffer convertImageData(BufferedImage bufferedImage) {
ByteBuffer imageBuffer;
WritableRaster raster;
BufferedImage texImage;
// find the closest power of 2 for the width and height
// of the produced texture
int texWidth = get2Fold(bufferedImage.getWidth());
int texHeight = get2Fold(bufferedImage.getHeight());
// create a raster that can be used by OpenGL as a source
// for a texture
if (bufferedImage.getColorModel().hasAlpha()) {
raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
texWidth, texHeight, 4, null);
texImage = new BufferedImage(this.glAlphaColorModel, raster, false,
new Hashtable<>());
} else {
raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
texWidth, texHeight, 3, null);
texImage = new BufferedImage(this.glColorModel, raster, false,
new Hashtable<>());
}
// copy the source image into the produced image
Graphics g = texImage.getGraphics();
g.setColor(new Color(0f, 0f, 0f, 0f));
g.fillRect(0, 0, texWidth, texHeight);
g.drawImage(bufferedImage, 0, 0, null);
g.dispose();
// build a byte buffer from the temporary image
// that be used by OpenGL to produce a texture.
byte[] data = ((DataBufferByte) texImage.getRaster().getDataBuffer())
.getData();
System.out.println("New Texture has dimensions: ("+texWidth+", "+texHeight+") and the data buffer is "+data.length+" bytes in size.");
byte[] tmp = new byte[data.length];
for(int i = 0 ; i < texHeight ; i++){
for(int j = 0; j < texWidth * 4 ; j++){
tmp[i * texWidth * 4 + j] = data[(texHeight - 1 - i) * texWidth * 4 + j];
}
}
data = tmp;
imageBuffer = ByteBuffer.allocateDirect(data.length);
imageBuffer.order(ByteOrder.nativeOrder());
imageBuffer.put(data, 0, data.length);
imageBuffer.flip();
return imageBuffer;
}
}