mmb.engine.texture.Textures 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.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
import org.joml.Vector2f;
import org.joml.Vector2fc;
import org.joml.Vector2i;
import org.joml.Vector4f;
import mmb.Main;
import mmb.NN;
import mmb.Nil;
import mmb.engine.NotFoundException;
import mmb.engine.debug.Debugger;
import mmb.engine.mods.ModLoader;
import monniasza.collects.Identifiable;
import monniasza.collects.selfset.HashSelfSet;
import monniasza.collects.selfset.SelfSet;
/**
* The texture library used by the MultiMachineBuilder
* @author oskar
*/
public class Textures {
private Textures() {}
private static final Debugger debug = new Debugger("TEXTURES");
@NN private static final BufferedImage DUMMY = new BufferedImage(1, 1, BufferedImage.TYPE_3BYTE_BGR);
//Raw data
private static final SelfSet<@NN String, @NN Texture> loadedTextures0 = HashSelfSet.createNonnull(Texture.class);
private static final TextureAtlas atlas = new TextureAtlas();
/**
* Loads a texture from raw data (PNG, JPEG or GIF)
* @param name texture name, without 'textures/' and with forward slashes only
* @param data texture data
* @return the loaded texture, or null if texture is unsupported or absent
* @throws IOException when texture fails to load
*/
public static Texture load(String name, @Nil InputStream data) throws IOException{
if(data == null) return null;
try {
BufferedImage image = ImageIO.read(data);
if(image == null) {
debug.printl("Failed to load "+name);
return null;
}
return load(name, image);
} catch (IOException e) {
debug.stacktraceError(e, "Failed to load "+name);
throw e;
}
}
/**
* Loads a texture from a {@link BufferedImage}
* @param name texture name, without 'textures/' and with forward slashes only
* @param data texture data
* @return the loaded texture, or null if texture is unsupported or absent
*/
public static Texture load(String name, BufferedImage data) {
String name2 = name.replace('\\', '/'); //replace slashes so users can use both '/' and '\'
debug.printl("Loading texture: "+name2);
Texture tex = atlas.insert(data, name2);
loadedTextures0.add(tex);
return tex;
}
/**
* Gets the texture as {@link BufferedImage}.
* To get as a {@link Texture}, use {@link #get1(String)} instead
* @param name texture name
* @return texture
* @throws NotFoundException if texture is not found
*/
@NN public static BufferedImage get(String name) {
if(!Main.isRunning()) return DUMMY;
return get1(name).img;
}
/**
* Gets the texture as {@link Texture}.
* To get as a {@link Texture}, use {@link #get(String)} instead
* @param name texture name
* @return texture
* @throws NotFoundException if texture is not found
*/
@NN public static Texture get1(String name) {
if(!Main.isRunning()) return null;
Texture result = loadedTextures0.get(name);
if(result == null) {
//Cache miss, load classpath
try(InputStream in = ModLoader.bcl.getResourceAsStream("textures/"+name)) {
if(in == null) throw new NotFoundException("Could not find texture "+name);
result = load(name, in);
if(result == null) throw new NotFoundException("Could not load texture "+name);
} catch (IOException e) {
throw new NotFoundException("Failed to load texture "+name, e);
}
}
return result;
}
/**
* A texture used by MultiMachineBuilder
* @author oskar
*/
public static class Texture implements Identifiable<@NN String>{
/** Left pixel X coordinate in texture atlas*/
public final int minx;
/** Upper pixel Y coordinate in texture atlas*/
public final int miny;
/** Right X coordinate in texture atlas */
public final int maxx;
/** Bottom Y coordinate in texture atlas */
public final int maxy;
/** The BufferedImage used in AWT-based graphics modules */
@NN public final BufferedImage img;
/** Texture path, with file extension, starting at the texture directory */
@NN public final String id;
private Vector4f lod;
/**
* Creates a texture node
* @discouraged Should be used only in the game engine, not in mods
* @param minx left pixel X coordinate in texture atlas
* @param miny upper pixel Y coordinate in texture atlas
* @param maxx right X coordinate in texture atlas
* @param maxy bottom Y coordinate in texture atlas
* @param img the BufferedImage used in AWT-based graphics modules
* @param id texture path, with file extension, starting at the texture directory
*/
public Texture(int minx, int miny, int maxx, int maxy, BufferedImage img, String id) {
this.minx = minx;
this.miny = miny;
this.maxx = maxx;
this.maxy = maxy;
this.img = img;
this.id = id;
}
/**
* Get the atlas coordinates using texture coordinates
* @param src texture coordinates
* @param dest write atlas coordinates here
* @return dest
*/
@NN public Vector2f uvconvert(Vector2fc src, Vector2f dest) {
return uvconvert(src.x(), src.y(), dest);
}
/**
* Get the atlas coordinates using texture coordinates
* @param x X texture coordinate
* @param y Y texture coordinate
* @param dest write atlas coordinates here
* @return dest
*/
@NN public Vector2f uvconvert(float x, float y, Vector2f dest) {
dest.x = ((maxx-minx)*x + minx + 0.0f)/atlas.image.getWidth();
dest.y = ((maxy-miny)*y + miny + 0.0f)/atlas.image.getHeight();
return dest;
}
@Override
@NN public String id() {
return id;
}
/**
* Replaces the vector with a LOD color
* @param vec vector to replace with a level of detail color
* @return vec
*/
public Vector4f LOD(Vector4f vec) {
if(lod == null) lod = LODs.calcLOD(img, new Vector4f());
return lod.get(vec);
}
}
//OpenGL stuff
private static boolean isInited;
/** Test method used to test atlasing capabilities*/
public static void displayAtlas() {
if(isInited) return;
isInited = true;
//Image to byte buffer conversion
BufferedImage image = atlas.image;
int[] pixels = new int[image.getWidth() * image.getHeight()];
image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
final int BYTES_PER_PIXEL = 4; //4 for RGBA, 3 for RGB
ByteBuffer buffer = ByteBuffer.allocateDirect(image.getWidth() * image.getHeight() * BYTES_PER_PIXEL);
for(int y = 0; y < image.getHeight(); y++){
for(int x = 0; x < image.getWidth(); x++){
int pixel = pixels[y * image.getWidth() + x];
buffer.put((byte) ((pixel >> 16) & 0xFF)); // Red component
buffer.put((byte) ((pixel >> 8) & 0xFF)); // Green component
buffer.put((byte) (pixel & 0xFF)); // Blue component
buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha component. Only for RGBA
}
}
buffer.flip(); //FOR THE LOVE OF GOD DO NOT FORGET THIS
atlasData = buffer;
}
private static ByteBuffer atlasData;
/** @return raw texture atlas data. Used for OpenGL renderer */
public static ByteBuffer getAtlas() {
if(atlasData == null) throw new IllegalStateException("Atlas data is not yet created");
return atlasData;
}
/**
* Gets the texture atlas size
* @param dest write atlas sze here
* @return dest
*/
public static Vector2i atlasSize(Vector2i dest) {
dest.x = atlas.image.getWidth();
dest.y = atlas.image.getHeight();
return dest;
}
}