implemented texture atlas
This commit is contained in:
parent
7c3ee28ba5
commit
f0e92638af
13
Test.java
13
Test.java
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
package com.danitheskunk.skunkworks;
|
package com.danitheskunk.skunkworks;
|
||||||
|
|
||||||
public interface ITexture {
|
public interface ITexture {
|
||||||
|
Vec2i getSize();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue