package gl_engine.texture; import static org.lwjgl.opengl.GL11.GL_NEAREST; import static org.lwjgl.opengl.GL11.GL_RGBA; import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER; import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER; import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE; import static org.lwjgl.opengl.GL11.glBindTexture; import static org.lwjgl.opengl.GL11.glGenTextures; import static org.lwjgl.opengl.GL11.glTexImage2D; import static org.lwjgl.opengl.GL11.glTexParameteri; import static org.lwjgl.opengl.GL30.glGenerateMipmap; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Comparator; import gl_engine.ResourceLoader; import gl_engine.range.Range2i; import gl_engine.vec.Vec2i; public class TextureAtlas2D { int texture; public int width, height; public ArrayList raw_textures; public ArrayList tex_refs; public TextureAtlas2D() { raw_textures = new ArrayList(); tex_refs = new ArrayList(); raw_textures.add(TextureRaw.createEmpty()); width = 0; height = 0; } public void add(TextureRaw tex) { raw_textures.add(tex); } public void clear() { raw_textures.clear(); raw_textures.add(TextureRaw.createEmpty()); } private static String getParentPath(String path) { int at = 0; byte[] path_b = path.getBytes(); for(int i=0;i= other.y + other.h || other.y >= check.y + check.h) { return false; } if(check.x >= other.x + other.w || other.x >= check.x + check.w) { return false; } return true; } private TextureRect refHasCollision(ArrayList refs, TextureRect other) { for(TextureRect ref : refs) { if(refHasCollision(ref, other)) { return ref; } } return null; } public void bind() { glBindTexture(GL_TEXTURE_2D, texture); } public void generate() { tex_refs.clear(); int size = 1; ArrayList tex_rects = new ArrayList(); TextureRect lastRect = null; raw_textures.sort(new Comparator() { @Override public int compare(TextureRaw o1, TextureRaw o2) { if(o1.height < o2.height) { return 1; } if(o1.height > o2.height) { return -1; } if(o1.width > o2.width) { return 1; } if(o1.width < o2.width) { return -1; } return 0; } }); long millis_now = System.currentTimeMillis(); long millis_last = millis_now; // Work out the positions of each rect for(int i=0;i 1000) { millis_last += 1000; System.out.println("Generating atlas " + i + "/" + raw_textures.size()); } TextureRaw tex = raw_textures.get(i); TextureRect rect = new TextureRect(); rect.r = tex; rect.w = tex.width; rect.h = tex.height; rect.x = 0; rect.y = 0; if(lastRect != null) { if(lastRect.h <= rect.h && lastRect.w <= rect.w) { rect.x = lastRect.x; rect.y = lastRect.y; } } while(true) { TextureRect collision = refHasCollision(tex_rects, rect); if(collision == null) { break; } int change = collision.x + collision.w; if(change != rect.x) { rect.x = change; } else { rect.x += 1; } if(rect.x + rect.w > size) { rect.y += 1; rect.x = 0; } if(rect.y + rect.h > size) { size *= 2; rect.x = 0; rect.y = 0; } } TextureRef2D ref = new TextureRef2D(); ref.texmap = this; ref.ref = tex.ref; ref.sx = rect.x; ref.sy = rect.y; ref.ex = rect.x + rect.w; ref.ey = rect.y + rect.h; lastRect = rect; tex_rects.add(rect); tex_refs.add(ref); if(rect.h > height) { height = rect.h; } } for(TextureRef2D ref : tex_refs) { ref.sx /= size; ref.ex /= size; ref.sy /= size; ref.ey /= size; } width = size; height = size; byte[] texmap_b = new byte[width*height*4]; Range2i texmap_r = new Range2i(width, height); TextureRect last_rect = null; for(int i=0;i 1000) { millis_last += 1000; System.out.println("Rendering atlas " + ((int)(i / ((double)width*height) * 1000)) / (double)10 + "%"); } if( last_rect != null && pos.x >= last_rect.x && pos.x < last_rect.x + last_rect.w && pos.y >= last_rect.y && pos.y < last_rect.y + last_rect.h ) { found = true; r = last_rect; } if(!found) { //System.out.println("hi"); for(TextureRect rect : tex_rects) { if( pos.x >= rect.x && pos.x < rect.x + rect.w && pos.y >= rect.y && pos.y < rect.y + rect.h ) { r = rect; last_rect = rect; found = true; break; } } } if(r == null) { texmap_b[i*4+0] = 0; texmap_b[i*4+1] = 0; texmap_b[i*4+2] = 0; texmap_b[i*4+3] = 0; continue; } Range2i tex_r = new Range2i(r.w, r.h); Vec2i tex_p = new Vec2i(pos.x - r.x, pos.y - r.y); int tex_id = tex_p.getId(tex_r); if(tex_p.x == r.w - 1 && tex_p.y == r.h - 1) { tex_rects.remove(r); } texmap_b[i*4+0] = r.r.bytes[tex_id*4+0]; texmap_b[i*4+1] = r.r.bytes[tex_id*4+1]; texmap_b[i*4+2] = r.r.bytes[tex_id*4+2]; texmap_b[i*4+3] = r.r.bytes[tex_id*4+3]; millis_now = System.currentTimeMillis(); } //System.out.println(Arrays.toString(texmap_b)); System.out.println("Atlas size: "+size+" x "+size); ByteBuffer texmap_buff = ByteBuffer.allocateDirect(texmap_b.length); texmap_buff.put(texmap_b); texmap_buff.position(0); texture = glGenTextures(); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texmap_buff); glGenerateMipmap(GL_TEXTURE_2D); raw_textures.clear(); } }