package jo.util.lwjgl.win;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.imageio.ImageIO;
import jo.sm.logic.utils.BufferLogic;
import jo.sm.logic.utils.IntegerUtils;
import org.lwjgl.opengl.GL11;
public class JGLTextureCache {
private static final Map<Integer, JGLTextureSpec> mSpecCache = new HashMap<>();
private static final Map<Integer, Integer> mLoadedCache = new HashMap<>();
private static final Set<Integer> mMRULoaded = new HashSet<>();
public static void register(int id, JGLTextureSpec spec) {
mSpecCache.put(id, spec);
}
public static void register(int id, String fileName) {
JGLTextureSpec spec = new JGLTextureSpec();
spec.setFileName(fileName);
register(id, spec);
}
public static void register(int id, BufferedImage img) {
JGLTextureSpec spec = new JGLTextureSpec();
spec.setImage(img);
register(id, spec);
}
public static void register(int id, String fileName, int left, int top, int width, int height) {
JGLTextureSpec spec = new JGLTextureSpec();
spec.setFileName(fileName);
spec.setLeft(left);
spec.setTop(top);
spec.setWidth(width);
spec.setHeight(height);
register(id, spec);
}
public static boolean isRegistered(int id) {
return mSpecCache.containsKey(id);
}
public static void markTextures() {
synchronized (mMRULoaded) {
mMRULoaded.clear();
}
}
public static void freeUnusedTextures() {
int[] unused = getUnUsedTextures();
System.out.println("Freeing gl#" + unused);
GL11.glDeleteTextures(IntBuffer.wrap(unused));
}
public static void freeAllTextures() {
int[] used = getUsedTextures();
GL11.glDeleteTextures(IntBuffer.wrap(used));
}
public static void useTexture(int textureID) {
synchronized (mMRULoaded) {
if (textureID == 0) {
return;
}
mMRULoaded.add(textureID);
}
}
public static int[] getUsedTextures() {
synchronized (mMRULoaded) {
return IntegerUtils.toArray(mMRULoaded.toArray());
}
}
public static int[] getUnUsedTextures() {
Set<Integer> unused = new HashSet<>();
synchronized (mMRULoaded) {
unused.addAll(mLoadedCache.keySet());
unused.removeAll(mMRULoaded);
}
return IntegerUtils.toArray(unused.toArray());
}
public static int getTexture(int textureID) {
useTexture(textureID);
GL11.glEnable(GL11.GL_TEXTURE_2D);
if (mLoadedCache.containsKey(textureID)) {
return mLoadedCache.get(textureID);
}
if (!mSpecCache.containsKey(textureID)) {
throw new IllegalArgumentException("Unknown texture ID=" + textureID);
}
int texture = genTexture();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
BufferedImage img = readImage(textureID);
boolean storeAlphaChannel = true; // TODO: work it out from image
ByteBuffer tex = readPixels(img, storeAlphaChannel);
makeRGBTexture(tex, img.getWidth(), img.getHeight(), storeAlphaChannel);
mLoadedCache.put(textureID, texture);
System.out.println("Binding texture ID#" + textureID + " to gl#" + texture);
return texture;
}
private static int genTexture() {
IntBuffer tmp = BufferLogic.createIntBuffer(1);
GL11.glGenTextures(tmp);
return tmp.get(0);
}
private static void makeRGBTexture(ByteBuffer img, int width, int height,
boolean storeAlphaChannel) {
int components = storeAlphaChannel ? 4 : 3;
int format = storeAlphaChannel ? GL11.GL_RGBA : GL11.GL_RGB;
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, components, width,
height, 0, format, GL11.GL_UNSIGNED_BYTE, img);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
}
private static BufferedImage readImage(int textureID) {
try {
JGLTextureSpec spec = mSpecCache.get(textureID);
if (spec.getImage() != null) {
return spec.getImage();
}
BufferedImage img = ImageIO.read(new File(spec.getFileName()));
if (spec.getLeft() >= 0) {
img = img.getSubimage(spec.getLeft(), spec.getTop(), spec.getWidth(), spec.getHeight());
}
spec.setImage(img);
return img;
} catch (IOException e) {
throw new IllegalArgumentException("Could not read image id=" + textureID, e);
}
}
private static ByteBuffer readPixels(BufferedImage img,
boolean storeAlphaChannel) {
int w = img.getWidth();
int h = img.getHeight();
ByteBuffer texBuf;
if (storeAlphaChannel) {
texBuf = ByteBuffer.allocateDirect(w * h * 4);
} else {
texBuf = ByteBuffer.allocateDirect(w * h * 3);
}
for (int i = h - 1; i >= 0; i--) {
for (int j = 0; j < w; j++) {
int pix = img.getRGB(j, i);
texBuf.put((byte) ((pix >> 16) & 0xff));// red
texBuf.put((byte) ((pix >> 8) & 0xff)); // green
texBuf.put((byte) ((pix) & 0xff)); // blue
if (storeAlphaChannel) {
texBuf.put((byte) ((pix >> 24) & 0xff));// alpha
}
}
}
texBuf.rewind();
return texBuf;
/*
int[] packedPixels = new int[img.getWidth() * img.getHeight()];
PixelGrabber pixelgrabber = new PixelGrabber(img, 0, 0, img.getWidth(),
img.getHeight(), packedPixels, 0, img.getWidth());
try
{
pixelgrabber.grabPixels();
}
catch (InterruptedException e)
{
throw new RuntimeException();
}
int bytesPerPixel = storeAlphaChannel ? 4 : 3;
// ByteBuffer unpackedPixels =
// BufferUtil.newByteBuffer(packedPixels.length * bytesPerPixel);
ByteBuffer unpackedPixels = ByteBuffer
.allocateDirect(packedPixels.length * bytesPerPixel);
for (int row = img.getHeight() - 1; row >= 0; row--)
{
for (int col = 0; col < img.getWidth(); col++)
{
int packedPixel = packedPixels[row * img.getWidth() + col];
unpackedPixels.put((byte)((packedPixel >> 16) & 0xFF));
unpackedPixels.put((byte)((packedPixel >> 8) & 0xFF));
unpackedPixels.put((byte)((packedPixel >> 0) & 0xFF));
if (storeAlphaChannel)
{
unpackedPixels.put((byte)((packedPixel >> 24) & 0xFF));
}
}
}
unpackedPixels.flip();
return new Texture(unpackedPixels, img.getWidth(), img.getHeight());
*/
}
}