Compare commits

...

3 Commits

Author SHA1 Message Date
DaniTheSkunk f0e92638af implemented texture atlas 2022-09-16 03:18:12 +02:00
DaniTheSkunk 7c3ee28ba5 added non-scalar and vec2f versions of div to vec2i 2022-09-16 03:10:00 +02:00
DaniTheSkunk 7ace9c3409 non-scalar multiply in vec2i 2022-09-16 03:00:20 +02:00
7 changed files with 125 additions and 17 deletions

View File

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

View File

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

View File

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

View File

@ -1,9 +1,12 @@
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.*;
@ -26,14 +29,63 @@ class GLTextureAtlas {
ITexture addTexture(Image img) {
//todo: do the actual texture stuff
this.img = img;
update();
var texture = new GLTexture(new Recti(new Vec2i(0, 0), img.getSize()));
//this.img = img;
var texture = new GLTexture(new Recti(new Vec2i(0, 0), img.getSize()), img);
textures.add(texture);
repack();
updateImage();
uploadToGpu();
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);
buf.put(img.getData());
buf.flip();
@ -50,4 +102,16 @@ class GLTextureAtlas {
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_TEXTURE_2D);
renderContext = new GLRenderContext();
textureAtlas = new GLTextureAtlas();
renderContext = new GLRenderContext(textureAtlas);
shouldClose = false;

View File

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

View File

@ -43,8 +43,26 @@ public final class Vec2i {
public static Vec2i mul(Vec2i a, int b) {
return new Vec2i(a.x * b, a.y * b);
}
public static Vec2i mul(Vec2i a, Vec2i b) {
return new Vec2i(a.x * b.x, a.y * b.y);
}
public static Vec2i div(Vec2i a, int b) {
return new Vec2i(a.x / b, a.y / b);
}
public static Vec2i div(Vec2i a, Vec2i b) {
return new Vec2i(a.x / b.x, a.y / b.y);
}
public static Vec2f divf(Vec2i a, double b) {
return new Vec2f(a.x / b, a.y / b);
}
public static Vec2f divf(Vec2i a, Vec2f b) {
return new Vec2f(a.x / b.x, a.y / b.y);
}
public static Vec2f divf(Vec2i a, int b) {
return new Vec2f(a.x / (double)b, a.y / (double)b);
}
public static Vec2f divf(Vec2i a, Vec2i b) {
return new Vec2f(a.x / (double)b.x, a.y / (double)b.y);
}
}