implemented texture atlas

This commit is contained in:
DaniTheSkunk 2022-09-16 03:18:12 +02:00
parent 7c3ee28ba5
commit f0e92638af
6 changed files with 107 additions and 17 deletions

View File

@ -4,10 +4,11 @@ public class Test {
public static void main(String[] args) { public static void main(String[] args) {
var engine = new Engine(); var engine = new Engine();
var window = engine.openWindow(1280, 720, "Skunkworks"); var window = engine.openWindow(1280, 720, "Skunkworks");
var img2 = engine.loadImage("C:\\art\\pixel stuff.png");
var img = engine.loadImage("C:\\Users\\dani\\Videos\\Screenshot 2022-06-25 17-00-59.png"); var img = engine.loadImage("C:\\Users\\dani\\Videos\\Screenshot 2022-06-25 17-00-59.png");
//var img = engine.loadImage("C:\\art\\kyoko.png"); var tex2 = window.loadTexture("C:\\art\\pixel stuff.png");
var tex = window.loadTexture("C:\\Users\\dani\\Videos\\Screenshot 2022-06-25 17-00-59.png"); //img.drawImage(img2, Vec2i.ZERO);
System.out.println(img.getPixel(new Vec2i(60, 60))); var tex = window.loadTexture(img);
while(!window.shouldClose()) { while(!window.shouldClose()) {
window.tick(); window.tick();
@ -17,9 +18,13 @@ public class Test {
// new Color(150, 200, 250) // new Color(150, 200, 250)
//); //);
renderContext.drawTextureRectangle( renderContext.drawTextureRectangle(
new Recti(100, 100, 100, 100), new Recti(0, 0, 1280, 720),
tex tex
); );
renderContext.drawTextureRectangle(
new Recti(new Vec2i(200, 100), tex2.getSize()),
tex2
);
window.renderFinish(renderContext); window.renderFinish(renderContext);
} }
} }

View File

@ -3,6 +3,11 @@ package com.danitheskunk.skunkworks;
import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.opengl.GL11.*;
public class GLRenderContext implements IRenderContext{ public class GLRenderContext implements IRenderContext{
private GLTextureAtlas atlas;
public GLRenderContext(GLTextureAtlas atlas) {
this.atlas = atlas;
}
@Override @Override
public void drawRectangle(Recti rect, Color color) { public void drawRectangle(Recti rect, Color color) {
var tl = rect.getTopLeft(); var tl = rect.getTopLeft();
@ -36,11 +41,18 @@ public class GLRenderContext implements IRenderContext{
@Override @Override
public void drawTextureRectangle(Recti rect, ITexture texture, Color color) { public void drawTextureRectangle(Recti rect, ITexture texture, Color color) {
var tex = (GLTexture)texture;
var tl = rect.getTopLeft(); var tl = rect.getTopLeft();
var tr = rect.getTopRight(); var tr = rect.getTopRight();
var bl = rect.getBottomLeft(); var bl = rect.getBottomLeft();
var br = rect.getBottomRight(); var br = rect.getBottomRight();
var ttl = Vec2i.divf(tex.getTexArea().getTopLeft(), atlas.getSize());
var ttr = Vec2i.divf(tex.getTexArea().getTopRight(), atlas.getSize());
var tbl = Vec2i.divf(tex.getTexArea().getBottomLeft(), atlas.getSize());
var tbr = Vec2i.divf(tex.getTexArea().getBottomRight(), atlas.getSize());
glColor4f( glColor4f(
color.getR() / 255.0f, color.getR() / 255.0f,
color.getG() / 255.0f, color.getG() / 255.0f,
@ -49,18 +61,18 @@ public class GLRenderContext implements IRenderContext{
); );
//counter clockwise triangles //counter clockwise triangles
glTexCoord2f(0.0f, 1.0f); glTexCoord2d(tbl.getX(), tbl.getY());
glVertex2i(bl.getX(), bl.getY()); glVertex2i(bl.getX(), bl.getY());
glTexCoord2f(1.0f, 0.0f); glTexCoord2d(ttr.getX(), ttr.getY());
glVertex2i(tr.getX(), tr.getY()); glVertex2i(tr.getX(), tr.getY());
glTexCoord2f(0.0f, 0.0f); glTexCoord2d(ttl.getX(), ttl.getY());
glVertex2i(tl.getX(), tl.getY()); glVertex2i(tl.getX(), tl.getY());
glTexCoord2f(1.0f, 0.0f); glTexCoord2d(ttr.getX(), ttr.getY());
glVertex2i(tr.getX(), tr.getY()); glVertex2i(tr.getX(), tr.getY());
glTexCoord2f(0.0f, 1.0f); glTexCoord2d(tbl.getX(), tbl.getY());
glVertex2i(bl.getX(), bl.getY()); glVertex2i(bl.getX(), bl.getY());
glTexCoord2f(1.0f, 1.0f); glTexCoord2d(tbr.getX(), tbr.getY());
glVertex2i(br.getX(), bl.getY()); glVertex2i(br.getX(), bl.getY());
} }
} }

View File

@ -2,13 +2,22 @@ package com.danitheskunk.skunkworks;
public class GLTexture implements ITexture { public class GLTexture implements ITexture {
private Recti texArea; private Recti texArea;
Image img; //for re-blitting onto texture atlas
GLTexture(Recti texArea) { GLTexture(Recti texArea, Image img) {
this.texArea = texArea; this.texArea = texArea;
this.img = img;
} }
//setters //setters
@Override
public Vec2i getSize() { return this.img.getSize(); }
void setTexArea(Recti texArea) { void setTexArea(Recti texArea) {
this.texArea = texArea; this.texArea = texArea;
} }
public Recti getTexArea() {
return texArea;
}
} }

View File

@ -1,9 +1,12 @@
package com.danitheskunk.skunkworks; package com.danitheskunk.skunkworks;
import org.lwjgl.BufferUtils; import org.lwjgl.BufferUtils;
import org.lwjgl.stb.STBRPContext;
import org.lwjgl.stb.STBRectPack;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.opengl.GL11.*;
@ -26,14 +29,63 @@ class GLTextureAtlas {
ITexture addTexture(Image img) { ITexture addTexture(Image img) {
//todo: do the actual texture stuff //todo: do the actual texture stuff
this.img = img; //this.img = img;
update(); var texture = new GLTexture(new Recti(new Vec2i(0, 0), img.getSize()), img);
var texture = new GLTexture(new Recti(new Vec2i(0, 0), img.getSize()));
textures.add(texture); textures.add(texture);
repack();
updateImage();
uploadToGpu();
return texture; return texture;
} }
void update() { 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());
}
void repack() {
int x = 0;
int y = 0;
int height;
textures.sort(new TextureHeightComparator().reversed());
height = textures.get(0).img.getHeight();
for(var tex : textures) {
//texture larger than atlas? resize atlas and try again
if(tex.img.getHeight() > img.getHeight() || tex.img.getWidth() > img.getWidth()) {
doubleAtlasSize();
repack();
return;
}
//row full? start the next row
if(img.getWidth() - x < tex.img.getWidth()) {
x = 0;
y += height;
height = tex.img.getHeight();
//not enough space for new row? resize atlas and try again
if(y + height > tex.img.getHeight()) {
doubleAtlasSize();
repack();
return;
}
}
//take space, advance to right
tex.setTexArea(new Recti(new Vec2i(x, y), tex.img.getSize()));
x += tex.img.getWidth();
}
}
void updateImage() {
for(var tex : textures) {
img.drawImage(tex.img, tex.getTexArea().getPos());
}
}
void uploadToGpu() {
var buf = BufferUtils.createByteBuffer(img.getData().length); var buf = BufferUtils.createByteBuffer(img.getData().length);
buf.put(img.getData()); buf.put(img.getData());
buf.flip(); buf.flip();
@ -50,4 +102,16 @@ class GLTextureAtlas {
buf buf
); );
} }
public Vec2i getSize() {
return img.getSize();
}
private class TextureHeightComparator implements Comparator<GLTexture> {
@Override
public int compare(GLTexture o1, GLTexture o2) {
return o1.img.getHeight() - o2.img.getHeight();
}
}
} }

View File

@ -38,8 +38,8 @@ public class GLWindow implements IWindow {
glEnable(GL_COLOR); glEnable(GL_COLOR);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
renderContext = new GLRenderContext();
textureAtlas = new GLTextureAtlas(); textureAtlas = new GLTextureAtlas();
renderContext = new GLRenderContext(textureAtlas);
shouldClose = false; shouldClose = false;

View File

@ -1,5 +1,5 @@
package com.danitheskunk.skunkworks; package com.danitheskunk.skunkworks;
public interface ITexture { public interface ITexture {
Vec2i getSize();
} }