mmb.engine.texture.TextureAtlas Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of multimachinebuilder Show documentation
Show all versions of multimachinebuilder Show documentation
Dependency for the MultiMachineBuilder, a voxel game about building an industrial empire in a finite world.
THIS RELEASE IS NOT PLAYABLE. To play the game, donwload from >ITCH.IO LINK HERE< or >GH releases link here<
The newest version!
/**
*
*/
package mmb.engine.texture;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import mmb.NN;
import mmb.Nil;
import mmb.engine.debug.Debugger;
import mmb.engine.texture.Textures.Texture;
/**
* A class to help make texture atlases
* Based on https://blackpawn.com/texts/lightmaps/
* @author oskar
*/
public class TextureAtlas{
/** Maximum size of the texture atlas */
public static int MAX_SIZE = 8192;
/** The top level texture atlas node */
public TextureAtlasNode atlas;
/** The conainer image */
public BufferedImage image;
private static final Debugger debug = new Debugger("TEXTURE ATLAS");
/** Creates a texture atlas */
public TextureAtlas() {
image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);
atlas = new TextureAtlasNode();
atlas.rect.setBounds(0, 0, 256, 256);
}
/**
* Inserts a texture into a texture atlas
* @param img texture to insert
* @param id texture ID
* @return a texture object
*/
@NN public Texture insert(BufferedImage img, String id) {
while(true) {
TextureAtlasNode result = atlas.insert(img, id);
if(result == null) {
//Insertion failed
if(image.getWidth() >= MAX_SIZE && image.getHeight() >= MAX_SIZE) throw new TextureError("Ran out of the texture size limit!");
if(image.getWidth() > image.getHeight()) {
int w = image.getWidth();
int h = image.getHeight()*2;
debug.printl("Size: "+w+"*"+h);
//Scale up the image vertically
BufferedImage img0 = new BufferedImage(w, h, image.getType());
//Copy data
Graphics g = img0.getGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
//Replace images
image = img0;
TextureAtlasNode overall = new TextureAtlasNode();
TextureAtlasNode upper = atlas;
TextureAtlasNode lower = new TextureAtlasNode();
overall.rect.width = upper.rect.width;
overall.rect.height = upper.rect.height * 2;
atlas = overall;
lower.rect.width = upper.rect.width;
lower.rect.height = upper.rect.height;
lower.rect.y = upper.rect.height;
overall.a = upper;
overall.b = lower;
}else {
int w = image.getWidth()*2;
int h = image.getHeight();
debug.printl("Size: "+w+"*"+h);
//Scale up the image horizontally
BufferedImage img0 = new BufferedImage(w, h, image.getType());
//Copy data
Graphics g = img0.getGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
//Replace images
image = img0;
TextureAtlasNode overall = new TextureAtlasNode();
TextureAtlasNode left = atlas;
TextureAtlasNode right = new TextureAtlasNode();
overall.rect.width = left.rect.width * 2;
overall.rect.height = left.rect.height;
atlas = overall;
right.rect.width = left.rect.width;
right.rect.height = left.rect.height;
right.rect.x = left.rect.width;
overall.a = left;
overall.b = right;
}
continue;
}
Graphics g = image.getGraphics();
g.drawImage(img, result.rect.x, result.rect.y, null);
g.dispose();
return new Texture(
result.rect.x, result.rect.y,
result.rect.x+result.rect.width, result.rect.y+result.rect.height,
img, id); //insertion successfull
}
}
/**
* A portion of the texture atlas
* @author oskar
*/
public static class TextureAtlasNode {
/** Left/top texture node */
@Nil public TextureAtlasNode a;
/** Right/bottom texture node */
@Nil public TextureAtlasNode b;
/** Ths node's border */
public final Rectangle rect = new Rectangle();
/** This node's texture ID */
public @Nil String textureID;
public TextureAtlasNode insert(BufferedImage img, String id) {
TextureAtlasNode aa = a;
TextureAtlasNode bb = b;
if(aa != null && bb != null) {
//not a leaf
TextureAtlasNode atlas = aa.insert(img, id);
if(atlas == null)
return bb.insert(img, id);
return atlas;
}
//leaf
if(textureID != null) return null; //if there's already a lightmap here, return
int width = img.getWidth();
int height = img.getHeight();
//(if we're too small, return)
if(width > rect.width || height > rect.height)
return null;
//if we're just right, accept
if(width == rect.width && height == rect.height) {
textureID = id;
return this;
}
//otherwise, gotta split this node and create some kids
TextureAtlasNode aaa = new TextureAtlasNode();
TextureAtlasNode bbb = new TextureAtlasNode();
a = aaa;
b = bbb;
//decide which way to split
int dw = rect.width - width;
int dh = rect.height - height;
if(dw > dh) {
//horizontal split
aaa.rect.setBounds(rect.x, rect.y,
width, rect.height);
bbb.rect.setBounds(rect.x+width, rect.y,
rect.width-width, rect.height);
}else {
//vertical split
aaa.rect.setBounds(rect.x, rect.y,
rect.width, height);
bbb.rect.setBounds(rect.x, rect.y+height,
rect.width, rect.height-height);
}
return aaa.insert(img, id);
}
}
}