135 lines
3.0 KiB
Java
135 lines
3.0 KiB
Java
package com.danitheskunk.skunkworks;
|
|
|
|
import org.lwjgl.BufferUtils;
|
|
import org.lwjgl.stb.STBRPContext;
|
|
import org.lwjgl.stb.STBRectPack;
|
|
|
|
import java.nio.ByteBuffer;
|
|
import java.util.ArrayList;
|
|
import java.util.Comparator;
|
|
import java.util.List;
|
|
|
|
import static org.lwjgl.opengl.GL11.*;
|
|
|
|
class GLTextureAtlas {
|
|
private GLTexture atlasTexture; //for debugging
|
|
private Image img;
|
|
private boolean shouldUpdate;
|
|
private int textureID;
|
|
private List<GLTexture> textures;
|
|
|
|
GLTextureAtlas() {
|
|
img = new Image(new Vec2i(32, 32));
|
|
textureID = glGenTextures();
|
|
textures = new ArrayList<>();
|
|
shouldUpdate = true;
|
|
|
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
}
|
|
|
|
ITexture addTexture(Image img) {
|
|
//todo: do the actual texture stuff
|
|
//this.img = img;
|
|
var texture = new GLTexture(new Recti(new Vec2i(0, 0), img.getSize()), img);
|
|
textures.add(texture);
|
|
shouldUpdate = true;
|
|
return texture;
|
|
}
|
|
|
|
void doubleAtlasSize() {
|
|
img = new Image(Vec2i.mul(img.getSize(), 2));
|
|
System.out.printf("Resized atlas to %dx%d\n", img.getSize().getX(), img.getSize().getY());
|
|
atlasTexture = new GLTexture(new Recti(Vec2i.ZERO, img.getSize()), img);
|
|
}
|
|
|
|
public void update() {
|
|
if(shouldUpdate) {
|
|
repack();
|
|
updateImage();
|
|
uploadToGpu();
|
|
shouldUpdate = false;
|
|
}
|
|
}
|
|
void repack() {
|
|
int x = 0;
|
|
int y = 0;
|
|
int height;
|
|
|
|
textures.sort(new TextureHeightComparator().reversed());
|
|
height = textures.get(0).getImg().getHeight();
|
|
|
|
for(var tex : textures) {
|
|
var teximg = tex.getImg();
|
|
//texture larger than atlas? resize atlas and try again
|
|
if(teximg.getHeight() > img.getHeight() || teximg.getWidth() > img.getWidth()) {
|
|
System.out.println("Texture too large");
|
|
doubleAtlasSize();
|
|
repack();
|
|
return;
|
|
}
|
|
|
|
//row full? start the next row
|
|
if(img.getWidth() - x < teximg.getWidth()) {
|
|
x = 0;
|
|
y += height;
|
|
height = teximg.getHeight();
|
|
|
|
//not enough space for new row? resize atlas and try again
|
|
if(y + height > img.getHeight()) {
|
|
System.out.println("Texture not enough space for new row");
|
|
doubleAtlasSize();
|
|
repack();
|
|
return;
|
|
}
|
|
}
|
|
|
|
//take space, advance to right
|
|
tex.setTexArea(new Recti(new Vec2i(x, y), teximg.getSize()));
|
|
x += teximg.getWidth();
|
|
}
|
|
}
|
|
|
|
void updateImage() {
|
|
for(var tex : textures) {
|
|
img.drawImage(tex.getImg(), tex.getTexArea().getPos());
|
|
}
|
|
}
|
|
|
|
void uploadToGpu() {
|
|
var buf = BufferUtils.createByteBuffer(img.getData().length);
|
|
buf.put(img.getData());
|
|
buf.flip();
|
|
|
|
glTexImage2D(
|
|
GL_TEXTURE_2D,
|
|
0,
|
|
GL_RGBA,
|
|
img.getWidth(),
|
|
img.getHeight(),
|
|
0,
|
|
GL_RGBA,
|
|
GL_UNSIGNED_BYTE,
|
|
buf
|
|
);
|
|
}
|
|
|
|
public GLTexture getAtlasTexture() {
|
|
return atlasTexture;
|
|
}
|
|
|
|
public Vec2i getSize() {
|
|
return img.getSize();
|
|
}
|
|
|
|
private class TextureHeightComparator implements Comparator<GLTexture> {
|
|
@Override
|
|
public int compare(GLTexture o1, GLTexture o2) {
|
|
return o1.getImg().getHeight() - o2.getImg().getHeight();
|
|
}
|
|
}
|
|
}
|
|
|