From 9656a1625fe52bd502a09739a0696d673aef4ab3 Mon Sep 17 00:00:00 2001 From: Maik Marschner Date: Sun, 10 Mar 2024 23:30:16 +0100 Subject: [PATCH 1/2] Generate item models from item textures. --- .../chunky/model/GeneratedItemModel.java | 240 ++++++++++++++++++ .../se/llbit/chunky/resources/Texture.java | 9 + 2 files changed, 249 insertions(+) create mode 100644 chunky/src/java/se/llbit/chunky/model/GeneratedItemModel.java diff --git a/chunky/src/java/se/llbit/chunky/model/GeneratedItemModel.java b/chunky/src/java/se/llbit/chunky/model/GeneratedItemModel.java new file mode 100644 index 000000000..881d96a7d --- /dev/null +++ b/chunky/src/java/se/llbit/chunky/model/GeneratedItemModel.java @@ -0,0 +1,240 @@ +package se.llbit.chunky.model; + +import se.llbit.chunky.resources.Texture; +import se.llbit.math.Quad; +import se.llbit.math.Ray; +import se.llbit.math.Vector3; +import se.llbit.math.Vector4; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * An item model that is generated from a texture by extruding it to some height and adding edges that match the texture. + * In other words, they look like the generated item models in Minecraft. + */ +public class GeneratedItemModel extends QuadModel { + private final Quad[] quads; + private final Texture[] textures; + + public GeneratedItemModel(Texture texture) { + quads = generateItemModelQuads(texture); + textures = new Texture[quads.length]; + Arrays.fill(textures, texture); + } + + @Override + public Quad[] getQuads() { + return quads; + } + + @Override + public Texture[] getTextures() { + return textures; + } + + public static Quad[] generateItemModelQuads(Texture tex) { + List quads = new ArrayList<>(); + quads.add(new Quad( + new Vector3(1, 0, 1), + new Vector3(0, 0, 1), + new Vector3(1, 0, 0), + new Vector4(1, 0, 0, 1) + )); + quads.add( + new Quad( + new Vector3(0, 1 / 16., 1), + new Vector3(1, 1 / 16., 1), + new Vector3(0, 1 / 16., 0), + new Vector4(0, 1, 0, 1) + )); + + { + // generate north facing edge quads + boolean edge = false; + int start = 0, length = 0; + for (int y = 0; y < tex.getHeight(); y++) { + for (int x = 0; x < tex.getWidth(); x++) { + if (tex.getAlpha(x, y) > Ray.EPSILON && ( + y == 0 || tex.getAlpha(x, y - 1) < Ray.EPSILON + )) { + if (edge) { + length++; + } else { + edge = true; + start = x; + length = 1; + } + } else if (edge) { + // edge ended + float fx = ((float) start) / tex.getWidth(); + float tx = ((float) start + length) / tex.getWidth(); + float fz = ((float) y) / tex.getHeight(); + float tz = (y + 1f) / tex.getHeight(); + quads.add(new Quad( + new Vector3(fx, 1 / 16., fz), + new Vector3(tx, 1 / 16., fz), + new Vector3(fx, 0, fz), + new Vector4(fx, tx, 1 - fz, 1 - tz) + )); + edge = false; + } + } + if (edge) { + float fx = ((float) start) / tex.getWidth(); + float tx = ((float) start + length) / tex.getWidth(); + float fz = ((float) y) / tex.getHeight(); + float tz = (y + 1f) / tex.getHeight(); + quads.add(new Quad( + new Vector3(fx, 1 / 16., fz), + new Vector3(tx, 1 / 16., fz), + new Vector3(fx, 0, fz), + new Vector4(fx, tx, 1 - fz, 1 - tz) + )); + edge = false; + } + } + } + { + // generate south facing edge quads + boolean edge = false; + int start = 0, length = 0; + for (int y = 0; y < tex.getHeight(); y++) { + for (int x = 0; x < tex.getWidth(); x++) { + if (tex.getAlpha(x, y) > Ray.EPSILON && ( + y == tex.getHeight() - 1 || tex.getAlpha(x, y + 1) < Ray.EPSILON + )) { + if (edge) { + length++; + } else { + edge = true; + start = x; + length = 1; + } + } else if (edge) { + // edge ended + float fx = ((float) start) / tex.getWidth(); + float tx = ((float) start + length) / tex.getWidth(); + float fz = ((float) y) / tex.getHeight(); + float tz = (y + 1f) / tex.getHeight(); + quads.add(new Quad( + new Vector3(tx, 1 / 16., tz), + new Vector3(fx, 1 / 16., tz), + new Vector3(tx, 0, tz), + new Vector4(tx, fx, 1 - fz, 1 - tz) + )); + edge = false; + } + } + if (edge) { + float fx = ((float) start) / tex.getWidth(); + float tx = ((float) start + length) / tex.getWidth(); + float fz = ((float) y) / tex.getHeight(); + float tz = (y + 1f) / tex.getHeight(); + quads.add(new Quad( + new Vector3(tx, 1 / 16., tz), + new Vector3(fx, 1 / 16., tz), + new Vector3(tx, 0, tz), + new Vector4(tx, fx, 1 - fz, 1 - tz) + )); + edge = false; + } + } + } + { + // generate west facing edge quads + boolean edge = false; + int start = 0, length = 0; + for (int x = 0; x < tex.getWidth(); x++) { + for (int y = 0; y < tex.getHeight(); y++) { + if (tex.getAlpha(x, y) > Ray.EPSILON && ( + x == 0 || tex.getAlpha(x - 1, y) < Ray.EPSILON + )) { + if (edge) { + length++; + } else { + edge = true; + start = y; + length = 1; + } + } else if (edge) { + // edge ended + float fz = ((float) start) / tex.getHeight(); + float tz = ((float) start + length) / tex.getHeight(); + float fx = ((float) x) / tex.getWidth(); + float tx = (x + 1f) / tex.getWidth(); + quads.add(new Quad( + new Vector3(fx, 1 / 16., fz), + new Vector3(fx, 0, fz), + new Vector3(fx, 1 / 16., tz), + new Vector4(fx, tx, 1 - fz, 1 - tz) + )); + edge = false; + } + } + if (edge) { + float fz = ((float) start) / tex.getHeight(); + float tz = ((float) start + length) / tex.getHeight(); + float fx = ((float) x) / tex.getWidth(); + float tx = (x + 1f) / tex.getWidth(); + quads.add(new Quad( + new Vector3(fx, 1 / 16., fz), + new Vector3(fx, 0, fz), + new Vector3(fx, 1 / 16., tz), + new Vector4(fx, tx, 1 - fz, 1 - tz) + )); + edge = false; + } + } + } + { + // generate east facing edge quads + boolean edge = false; + int start = 0, length = 0; + for (int x = 0; x < tex.getWidth(); x++) { + for (int y = 0; y < tex.getHeight(); y++) { + if (tex.getAlpha(x, y) > Ray.EPSILON && ( + x == tex.getWidth() - 1 || tex.getAlpha(x + 1, y) < Ray.EPSILON + )) { + if (edge) { + length++; + } else { + edge = true; + start = y; + length = 1; + } + } else if (edge) { + // edge ended + float fz = ((float) start) / tex.getHeight(); + float tz = ((float) start + length) / tex.getHeight(); + float fx = ((float) x) / tex.getWidth(); + float tx = (x + 1f) / tex.getWidth(); + quads.add(new Quad( + new Vector3(tx, 0, fz), + new Vector3(tx, 1 / 16., fz), + new Vector3(tx, 0, tz), + new Vector4(fx, tx, 1 - fz, 1 - tz) + )); + edge = false; + } + } + if (edge) { + float fz = ((float) start) / tex.getHeight(); + float tz = ((float) start + length) / tex.getHeight(); + float fx = ((float) x) / tex.getWidth(); + float tx = (x + 1f) / tex.getWidth(); + quads.add(new Quad( + new Vector3(tx, 0, fz), + new Vector3(tx, 1 / 16., fz), + new Vector3(tx, 0, tz), + new Vector4(fx, tx, 1 - fz, 1 - tz) + )); + edge = false; + } + } + } + + return quads.toArray(new Quad[0]); + } +} diff --git a/chunky/src/java/se/llbit/chunky/resources/Texture.java b/chunky/src/java/se/llbit/chunky/resources/Texture.java index bb3184533..e2f23e4a2 100644 --- a/chunky/src/java/se/llbit/chunky/resources/Texture.java +++ b/chunky/src/java/se/llbit/chunky/resources/Texture.java @@ -1582,6 +1582,15 @@ public float[] getColor(int x, int y) { return result; } + /** + * Get alpha channel value + * + * @return alpha value as float between 0 and 1 + */ + public float getAlpha(int x, int y) { + return (image.data[width * y + x] >>> 24) / 255.0f; + } + /** * Get bilinear interpolated color value. */ From 0b8fbcb555138147267da29d637c39e19fa1391d Mon Sep 17 00:00:00 2001 From: Maik Marschner Date: Sun, 10 Mar 2024 23:41:35 +0100 Subject: [PATCH 2/2] Render campfire items. --- .../chunky/block/minecraft/Campfire.java | 79 +-- .../java/se/llbit/chunky/entity/Campfire.java | 522 ++++++++++-------- 2 files changed, 339 insertions(+), 262 deletions(-) diff --git a/chunky/src/java/se/llbit/chunky/block/minecraft/Campfire.java b/chunky/src/java/se/llbit/chunky/block/minecraft/Campfire.java index 42c4d5949..abc296dcf 100644 --- a/chunky/src/java/se/llbit/chunky/block/minecraft/Campfire.java +++ b/chunky/src/java/se/llbit/chunky/block/minecraft/Campfire.java @@ -25,51 +25,58 @@ import se.llbit.math.Ray; import se.llbit.math.Vector3; import se.llbit.nbt.CompoundTag; +import se.llbit.nbt.ListTag; import java.util.Random; public class Campfire extends MinecraftBlockTranslucent { - private final se.llbit.chunky.entity.Campfire.Kind kind; - private final String facing; - public final boolean isLit; + private final se.llbit.chunky.entity.Campfire.Kind kind; + private final String facing; + public final boolean isLit; - public Campfire(String name, se.llbit.chunky.entity.Campfire.Kind kind, String facing, boolean lit) { - super(name, Texture.campfireLog); - invisible = true; - opaque = false; - localIntersect = true; - this.kind = kind; - this.facing = facing; - this.isLit = lit; - } + public Campfire(String name, se.llbit.chunky.entity.Campfire.Kind kind, String facing, boolean lit) { + super(name, Texture.campfireLog); + invisible = true; + opaque = false; + localIntersect = true; + this.kind = kind; + this.facing = facing; + this.isLit = lit; + } - @Override - public boolean intersect(Ray ray, Scene scene) { - return false; - } + @Override + public boolean intersect(Ray ray, Scene scene) { + return false; + } - @Override - public boolean isBlockEntity() { - return true; - } + @Override + public boolean isBlockEntity() { + return true; + } - @Override - public Entity toBlockEntity(Vector3 position, CompoundTag entityTag) { - return new se.llbit.chunky.entity.Campfire(this.kind, position, this.facing, this.isLit, this); - } + @Override + public Entity toBlockEntity(Vector3 position, CompoundTag entityTag) { + ListTag items = entityTag.get("Items").asList(); + return new se.llbit.chunky.entity.Campfire(this.kind, position, this.facing, this.isLit, this, + !items.isEmpty() ? items.get(0).get("id").stringValue(null) : null, + items.size() >= 2 ? items.get(1).get("id").stringValue(null) : null, + items.size() >= 3 ? items.get(2).get("id").stringValue(null) : null, + items.size() >= 4 ? items.get(3).get("id").stringValue(null) : null + ); + } - @Override - public int faceCount() { - return se.llbit.chunky.entity.Campfire.faceCount(); - } + @Override + public int faceCount() { + return se.llbit.chunky.entity.Campfire.faceCount(); + } - @Override - public void sample(int face, Vector3 loc, Random rand) { - se.llbit.chunky.entity.Campfire.sample(face, loc, rand); - } + @Override + public void sample(int face, Vector3 loc, Random rand) { + se.llbit.chunky.entity.Campfire.sample(face, loc, rand); + } - @Override - public double surfaceArea(int face) { - return se.llbit.chunky.entity.Campfire.surfaceArea(face); - } + @Override + public double surfaceArea(int face) { + return se.llbit.chunky.entity.Campfire.surfaceArea(face); + } } diff --git a/chunky/src/java/se/llbit/chunky/entity/Campfire.java b/chunky/src/java/se/llbit/chunky/entity/Campfire.java index 36c843686..76bb1368b 100644 --- a/chunky/src/java/se/llbit/chunky/entity/Campfire.java +++ b/chunky/src/java/se/llbit/chunky/entity/Campfire.java @@ -1,14 +1,17 @@ package se.llbit.chunky.entity; -import java.util.Collection; -import java.util.LinkedList; -import java.util.Random; - import se.llbit.chunky.block.Block; +import se.llbit.chunky.model.GeneratedItemModel; import se.llbit.chunky.model.Model; +import se.llbit.chunky.resources.ResourcePackLoader; +import se.llbit.chunky.resources.ResourcePackTextureLoader; import se.llbit.chunky.resources.Texture; +import se.llbit.chunky.resources.TextureCache; +import se.llbit.chunky.resources.texturepack.SimpleTexture; +import se.llbit.chunky.resources.texturepack.TextureLoader; import se.llbit.chunky.world.Material; import se.llbit.chunky.world.material.TextureMaterial; +import se.llbit.json.JsonArray; import se.llbit.json.JsonObject; import se.llbit.json.JsonValue; import se.llbit.log.Log; @@ -16,6 +19,10 @@ import se.llbit.math.primitive.Primitive; import se.llbit.util.JsonUtil; +import java.util.Collection; +import java.util.LinkedList; +import java.util.Random; + public class Campfire extends Entity { public enum Kind { @@ -34,218 +41,237 @@ public enum Kind { private static final Texture soullitlog = Texture.soulCampfireLogLit; private static final Texture[] tex = new Texture[]{ - log, log, log, log, log, log, log, log, log, log, log, log, log, log, log, - log, log, log, log, log, log, log, log, log, log, log, log, log, + log, log, log, log, log, log, log, log, log, log, log, log, log, log, log, + log, log, log, log, log, log, log, log, log, log, log, log, log, }; private static final Texture[] texLitCampfire = new Texture[]{ - log, log, log, litlog, log, log, log, litlog, log, log, litlog, litlog, log, log, litlog, - log, log, log, log, litlog, log, log, litlog, litlog, litlog, log, log, log + log, log, log, litlog, log, log, log, litlog, log, log, litlog, litlog, log, log, litlog, + log, log, log, log, litlog, log, log, litlog, litlog, litlog, log, log, log }; private static final Texture[] texLitSoulCampfire = new Texture[]{ - log, log, log, soullitlog, log, log, log, soullitlog, log, log, soullitlog, soullitlog, log, - log, soullitlog, - log, log, log, log, soullitlog, log, log, soullitlog, soullitlog, soullitlog, log, log, log + log, log, log, soullitlog, log, log, log, soullitlog, log, log, soullitlog, soullitlog, log, + log, soullitlog, + log, log, log, log, soullitlog, log, log, soullitlog, soullitlog, soullitlog, log, log, log }; private static final Quad[] quads = new Quad[]{ - new Quad( - new Vector3(5 / 16.0, 4 / 16.0, 16 / 16.0), - new Vector3(5 / 16.0, 4 / 16.0, 0 / 16.0), - new Vector3(1 / 16.0, 4 / 16.0, 16 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 12 / 16.0, 16 / 16.0) - ), - new Quad( - new Vector3(5 / 16.0, 0 / 16.0, 0 / 16.0), - new Vector3(5 / 16.0, 0 / 16.0, 16 / 16.0), - new Vector3(1 / 16.0, 0 / 16.0, 0 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 12 / 16.0, 16 / 16.0) - ), - new Quad( - new Vector3(1 / 16.0, 4 / 16.0, 16 / 16.0), - new Vector3(1 / 16.0, 4 / 16.0, 0 / 16.0), - new Vector3(1 / 16.0, 0 / 16.0, 16 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 16 / 16.0, 12 / 16.0) - ), - new Quad( - new Vector3(5 / 16.0, 4 / 16.0, 0 / 16.0), - new Vector3(5 / 16.0, 4 / 16.0, 16 / 16.0), - new Vector3(5 / 16.0, 0 / 16.0, 0 / 16.0), - new Vector4(16 / 16.0, 0 / 16.0, 15 / 16.0, 11 / 16.0) - ), - new Quad( - new Vector3(1 / 16.0, 4 / 16.0, 0 / 16.0), - new Vector3(5 / 16.0, 4 / 16.0, 0 / 16.0), - new Vector3(1 / 16.0, 0 / 16.0, 0 / 16.0), - new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) - ), - new Quad( - new Vector3(5 / 16.0, 4 / 16.0, 16 / 16.0), - new Vector3(1 / 16.0, 4 / 16.0, 16 / 16.0), - new Vector3(5 / 16.0, 0 / 16.0, 16 / 16.0), - new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) - ), - new Quad( - new Vector3(16 / 16.0, 7 / 16.0, 11 / 16.0), - new Vector3(0 / 16.0, 7 / 16.0, 11 / 16.0), - new Vector3(16 / 16.0, 7 / 16.0, 15 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 12 / 16.0, 16 / 16.0) - ), - new Quad( - new Vector3(0 / 16.0, 3 / 16.0, 11 / 16.0), - new Vector3(16 / 16.0, 3 / 16.0, 11 / 16.0), - new Vector3(0 / 16.0, 3 / 16.0, 15 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 8 / 16.0, 12 / 16.0) - ), - new Quad( - new Vector3(0 / 16.0, 7 / 16.0, 15 / 16.0), - new Vector3(0 / 16.0, 7 / 16.0, 11 / 16.0), - new Vector3(0 / 16.0, 3 / 16.0, 15 / 16.0), - new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) - ), - new Quad( - new Vector3(16 / 16.0, 7 / 16.0, 11 / 16.0), - new Vector3(16 / 16.0, 7 / 16.0, 15 / 16.0), - new Vector3(16 / 16.0, 3 / 16.0, 11 / 16.0), - new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) - ), - new Quad( - new Vector3(0 / 16.0, 7 / 16.0, 11 / 16.0), - new Vector3(16 / 16.0, 7 / 16.0, 11 / 16.0), - new Vector3(0 / 16.0, 3 / 16.0, 11 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 16 / 16.0, 12 / 16.0) - ), - new Quad( - new Vector3(16 / 16.0, 7 / 16.0, 15 / 16.0), - new Vector3(0 / 16.0, 7 / 16.0, 15 / 16.0), - new Vector3(16 / 16.0, 3 / 16.0, 15 / 16.0), - new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 12 / 16.0) - ), - new Quad( - new Vector3(15 / 16.0, 4 / 16.0, 16 / 16.0), - new Vector3(15 / 16.0, 4 / 16.0, 0 / 16.0), - new Vector3(11 / 16.0, 4 / 16.0, 16 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 12 / 16.0, 16 / 16.0) - ), - new Quad( - new Vector3(15 / 16.0, 0 / 16.0, 0 / 16.0), - new Vector3(15 / 16.0, 0 / 16.0, 16 / 16.0), - new Vector3(11 / 16.0, 0 / 16.0, 0 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 12 / 16.0, 16 / 16.0) - ), - new Quad( - new Vector3(11 / 16.0, 4 / 16.0, 16 / 16.0), - new Vector3(11 / 16.0, 4 / 16.0, 0 / 16.0), - new Vector3(11 / 16.0, 0 / 16.0, 16 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 15 / 16.0, 11 / 16.0) - ), - new Quad( - new Vector3(15 / 16.0, 4 / 16.0, 0 / 16.0), - new Vector3(15 / 16.0, 4 / 16.0, 16 / 16.0), - new Vector3(15 / 16.0, 0 / 16.0, 0 / 16.0), - new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 12 / 16.0) - ), - new Quad( - new Vector3(11 / 16.0, 4 / 16.0, 0 / 16.0), - new Vector3(15 / 16.0, 4 / 16.0, 0 / 16.0), - new Vector3(11 / 16.0, 0 / 16.0, 0 / 16.0), - new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) - ), - new Quad( - new Vector3(15 / 16.0, 4 / 16.0, 16 / 16.0), - new Vector3(11 / 16.0, 4 / 16.0, 16 / 16.0), - new Vector3(15 / 16.0, 0 / 16.0, 16 / 16.0), - new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) - ), - new Quad( - new Vector3(16 / 16.0, 7 / 16.0, 1 / 16.0), - new Vector3(0 / 16.0, 7 / 16.0, 1 / 16.0), - new Vector3(16 / 16.0, 7 / 16.0, 5 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 12 / 16.0, 16 / 16.0) - ), - new Quad( - new Vector3(0 / 16.0, 3 / 16.0, 1 / 16.0), - new Vector3(16 / 16.0, 3 / 16.0, 1 / 16.0), - new Vector3(0 / 16.0, 3 / 16.0, 5 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 8 / 16.0, 12 / 16.0) - ), - new Quad( - new Vector3(0 / 16.0, 7 / 16.0, 5 / 16.0), - new Vector3(0 / 16.0, 7 / 16.0, 1 / 16.0), - new Vector3(0 / 16.0, 3 / 16.0, 5 / 16.0), - new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) - ), - new Quad( - new Vector3(16 / 16.0, 7 / 16.0, 1 / 16.0), - new Vector3(16 / 16.0, 7 / 16.0, 5 / 16.0), - new Vector3(16 / 16.0, 3 / 16.0, 1 / 16.0), - new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) - ), - new Quad( - new Vector3(0 / 16.0, 7 / 16.0, 1 / 16.0), - new Vector3(16 / 16.0, 7 / 16.0, 1 / 16.0), - new Vector3(0 / 16.0, 3 / 16.0, 1 / 16.0), - new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 12 / 16.0) - ), - new Quad( - new Vector3(16 / 16.0, 7 / 16.0, 5 / 16.0), - new Vector3(0 / 16.0, 7 / 16.0, 5 / 16.0), - new Vector3(16 / 16.0, 3 / 16.0, 5 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 16 / 16.0, 12 / 16.0) - ), - new Quad( - new Vector3(11 / 16.0, 1 / 16.0, 16 / 16.0), - new Vector3(11 / 16.0, 1 / 16.0, 0 / 16.0), - new Vector3(5 / 16.0, 1 / 16.0, 16 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 2 / 16.0, 8 / 16.0) - ), - new Quad( - new Vector3(11 / 16.0, 0 / 16.0, 0 / 16.0), - new Vector3(11 / 16.0, 0 / 16.0, 16 / 16.0), - new Vector3(5 / 16.0, 0 / 16.0, 0 / 16.0), - new Vector4(0 / 16.0, 16 / 16.0, 2 / 16.0, 8 / 16.0) - ), - new Quad( - new Vector3(5 / 16.0, 1 / 16.0, 0 / 16.0), - new Vector3(11 / 16.0, 1 / 16.0, 0 / 16.0), - new Vector3(5 / 16.0, 0 / 16.0, 0 / 16.0), - new Vector4(6 / 16.0, 0 / 16.0, 1 / 16.0, 0 / 16.0) - ), - new Quad( - new Vector3(11 / 16.0, 1 / 16.0, 16 / 16.0), - new Vector3(5 / 16.0, 1 / 16.0, 16 / 16.0), - new Vector3(11 / 16.0, 0 / 16.0, 16 / 16.0), - new Vector4(16 / 16.0, 10 / 16.0, 1 / 16.0, 0 / 16.0) - ), - rotateFire(new Quad( - new Vector3(0.8 / 16.0, 17 / 16.0, 8 / 16.0), - new Vector3(15.2 / 16.0, 17 / 16.0, 8 / 16.0), - new Vector3(0.8 / 16.0, 1 / 16.0, 8 / 16.0), - new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 0 / 16.0) - )), - rotateFire(new Quad( - new Vector3(15.2 / 16.0, 17 / 16.0, 8 / 16.0), - new Vector3(0.8 / 16.0, 17 / 16.0, 8 / 16.0), - new Vector3(15.2 / 16.0, 1 / 16.0, 8 / 16.0), - new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 0 / 16.0) - )), - rotateFire(new Quad( - new Vector3(8 / 16.0, 17 / 16.0, 15.2 / 16.0), - new Vector3(8 / 16.0, 17 / 16.0, 0.8 / 16.0), - new Vector3(8 / 16.0, 1 / 16.0, 15.2 / 16.0), - new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 0 / 16.0) - )), - rotateFire(new Quad( - new Vector3(8 / 16.0, 17 / 16.0, 0.8 / 16.0), - new Vector3(8 / 16.0, 17 / 16.0, 15.2 / 16.0), - new Vector3(8 / 16.0, 1 / 16.0, 0.8 / 16.0), - new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 0 / 16.0) - )) + new Quad( + new Vector3(5 / 16.0, 4 / 16.0, 16 / 16.0), + new Vector3(5 / 16.0, 4 / 16.0, 0 / 16.0), + new Vector3(1 / 16.0, 4 / 16.0, 16 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 12 / 16.0, 16 / 16.0) + ), + new Quad( + new Vector3(5 / 16.0, 0 / 16.0, 0 / 16.0), + new Vector3(5 / 16.0, 0 / 16.0, 16 / 16.0), + new Vector3(1 / 16.0, 0 / 16.0, 0 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 12 / 16.0, 16 / 16.0) + ), + new Quad( + new Vector3(1 / 16.0, 4 / 16.0, 16 / 16.0), + new Vector3(1 / 16.0, 4 / 16.0, 0 / 16.0), + new Vector3(1 / 16.0, 0 / 16.0, 16 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 16 / 16.0, 12 / 16.0) + ), + new Quad( + new Vector3(5 / 16.0, 4 / 16.0, 0 / 16.0), + new Vector3(5 / 16.0, 4 / 16.0, 16 / 16.0), + new Vector3(5 / 16.0, 0 / 16.0, 0 / 16.0), + new Vector4(16 / 16.0, 0 / 16.0, 15 / 16.0, 11 / 16.0) + ), + new Quad( + new Vector3(1 / 16.0, 4 / 16.0, 0 / 16.0), + new Vector3(5 / 16.0, 4 / 16.0, 0 / 16.0), + new Vector3(1 / 16.0, 0 / 16.0, 0 / 16.0), + new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) + ), + new Quad( + new Vector3(5 / 16.0, 4 / 16.0, 16 / 16.0), + new Vector3(1 / 16.0, 4 / 16.0, 16 / 16.0), + new Vector3(5 / 16.0, 0 / 16.0, 16 / 16.0), + new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) + ), + new Quad( + new Vector3(16 / 16.0, 7 / 16.0, 11 / 16.0), + new Vector3(0 / 16.0, 7 / 16.0, 11 / 16.0), + new Vector3(16 / 16.0, 7 / 16.0, 15 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 12 / 16.0, 16 / 16.0) + ), + new Quad( + new Vector3(0 / 16.0, 3 / 16.0, 11 / 16.0), + new Vector3(16 / 16.0, 3 / 16.0, 11 / 16.0), + new Vector3(0 / 16.0, 3 / 16.0, 15 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 8 / 16.0, 12 / 16.0) + ), + new Quad( + new Vector3(0 / 16.0, 7 / 16.0, 15 / 16.0), + new Vector3(0 / 16.0, 7 / 16.0, 11 / 16.0), + new Vector3(0 / 16.0, 3 / 16.0, 15 / 16.0), + new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) + ), + new Quad( + new Vector3(16 / 16.0, 7 / 16.0, 11 / 16.0), + new Vector3(16 / 16.0, 7 / 16.0, 15 / 16.0), + new Vector3(16 / 16.0, 3 / 16.0, 11 / 16.0), + new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) + ), + new Quad( + new Vector3(0 / 16.0, 7 / 16.0, 11 / 16.0), + new Vector3(16 / 16.0, 7 / 16.0, 11 / 16.0), + new Vector3(0 / 16.0, 3 / 16.0, 11 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 16 / 16.0, 12 / 16.0) + ), + new Quad( + new Vector3(16 / 16.0, 7 / 16.0, 15 / 16.0), + new Vector3(0 / 16.0, 7 / 16.0, 15 / 16.0), + new Vector3(16 / 16.0, 3 / 16.0, 15 / 16.0), + new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 12 / 16.0) + ), + new Quad( + new Vector3(15 / 16.0, 4 / 16.0, 16 / 16.0), + new Vector3(15 / 16.0, 4 / 16.0, 0 / 16.0), + new Vector3(11 / 16.0, 4 / 16.0, 16 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 12 / 16.0, 16 / 16.0) + ), + new Quad( + new Vector3(15 / 16.0, 0 / 16.0, 0 / 16.0), + new Vector3(15 / 16.0, 0 / 16.0, 16 / 16.0), + new Vector3(11 / 16.0, 0 / 16.0, 0 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 12 / 16.0, 16 / 16.0) + ), + new Quad( + new Vector3(11 / 16.0, 4 / 16.0, 16 / 16.0), + new Vector3(11 / 16.0, 4 / 16.0, 0 / 16.0), + new Vector3(11 / 16.0, 0 / 16.0, 16 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 15 / 16.0, 11 / 16.0) + ), + new Quad( + new Vector3(15 / 16.0, 4 / 16.0, 0 / 16.0), + new Vector3(15 / 16.0, 4 / 16.0, 16 / 16.0), + new Vector3(15 / 16.0, 0 / 16.0, 0 / 16.0), + new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 12 / 16.0) + ), + new Quad( + new Vector3(11 / 16.0, 4 / 16.0, 0 / 16.0), + new Vector3(15 / 16.0, 4 / 16.0, 0 / 16.0), + new Vector3(11 / 16.0, 0 / 16.0, 0 / 16.0), + new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) + ), + new Quad( + new Vector3(15 / 16.0, 4 / 16.0, 16 / 16.0), + new Vector3(11 / 16.0, 4 / 16.0, 16 / 16.0), + new Vector3(15 / 16.0, 0 / 16.0, 16 / 16.0), + new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) + ), + new Quad( + new Vector3(16 / 16.0, 7 / 16.0, 1 / 16.0), + new Vector3(0 / 16.0, 7 / 16.0, 1 / 16.0), + new Vector3(16 / 16.0, 7 / 16.0, 5 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 12 / 16.0, 16 / 16.0) + ), + new Quad( + new Vector3(0 / 16.0, 3 / 16.0, 1 / 16.0), + new Vector3(16 / 16.0, 3 / 16.0, 1 / 16.0), + new Vector3(0 / 16.0, 3 / 16.0, 5 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 8 / 16.0, 12 / 16.0) + ), + new Quad( + new Vector3(0 / 16.0, 7 / 16.0, 5 / 16.0), + new Vector3(0 / 16.0, 7 / 16.0, 1 / 16.0), + new Vector3(0 / 16.0, 3 / 16.0, 5 / 16.0), + new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) + ), + new Quad( + new Vector3(16 / 16.0, 7 / 16.0, 1 / 16.0), + new Vector3(16 / 16.0, 7 / 16.0, 5 / 16.0), + new Vector3(16 / 16.0, 3 / 16.0, 1 / 16.0), + new Vector4(4 / 16.0, 0 / 16.0, 12 / 16.0, 8 / 16.0) + ), + new Quad( + new Vector3(0 / 16.0, 7 / 16.0, 1 / 16.0), + new Vector3(16 / 16.0, 7 / 16.0, 1 / 16.0), + new Vector3(0 / 16.0, 3 / 16.0, 1 / 16.0), + new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 12 / 16.0) + ), + new Quad( + new Vector3(16 / 16.0, 7 / 16.0, 5 / 16.0), + new Vector3(0 / 16.0, 7 / 16.0, 5 / 16.0), + new Vector3(16 / 16.0, 3 / 16.0, 5 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 16 / 16.0, 12 / 16.0) + ), + new Quad( + new Vector3(11 / 16.0, 1 / 16.0, 16 / 16.0), + new Vector3(11 / 16.0, 1 / 16.0, 0 / 16.0), + new Vector3(5 / 16.0, 1 / 16.0, 16 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 2 / 16.0, 8 / 16.0) + ), + new Quad( + new Vector3(11 / 16.0, 0 / 16.0, 0 / 16.0), + new Vector3(11 / 16.0, 0 / 16.0, 16 / 16.0), + new Vector3(5 / 16.0, 0 / 16.0, 0 / 16.0), + new Vector4(0 / 16.0, 16 / 16.0, 2 / 16.0, 8 / 16.0) + ), + new Quad( + new Vector3(5 / 16.0, 1 / 16.0, 0 / 16.0), + new Vector3(11 / 16.0, 1 / 16.0, 0 / 16.0), + new Vector3(5 / 16.0, 0 / 16.0, 0 / 16.0), + new Vector4(6 / 16.0, 0 / 16.0, 1 / 16.0, 0 / 16.0) + ), + new Quad( + new Vector3(11 / 16.0, 1 / 16.0, 16 / 16.0), + new Vector3(5 / 16.0, 1 / 16.0, 16 / 16.0), + new Vector3(11 / 16.0, 0 / 16.0, 16 / 16.0), + new Vector4(16 / 16.0, 10 / 16.0, 1 / 16.0, 0 / 16.0) + ), + rotateFire(new Quad( + new Vector3(0.8 / 16.0, 17 / 16.0, 8 / 16.0), + new Vector3(15.2 / 16.0, 17 / 16.0, 8 / 16.0), + new Vector3(0.8 / 16.0, 1 / 16.0, 8 / 16.0), + new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 0 / 16.0) + )), + rotateFire(new Quad( + new Vector3(15.2 / 16.0, 17 / 16.0, 8 / 16.0), + new Vector3(0.8 / 16.0, 17 / 16.0, 8 / 16.0), + new Vector3(15.2 / 16.0, 1 / 16.0, 8 / 16.0), + new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 0 / 16.0) + )), + rotateFire(new Quad( + new Vector3(8 / 16.0, 17 / 16.0, 15.2 / 16.0), + new Vector3(8 / 16.0, 17 / 16.0, 0.8 / 16.0), + new Vector3(8 / 16.0, 1 / 16.0, 15.2 / 16.0), + new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 0 / 16.0) + )), + rotateFire(new Quad( + new Vector3(8 / 16.0, 17 / 16.0, 0.8 / 16.0), + new Vector3(8 / 16.0, 17 / 16.0, 15.2 / 16.0), + new Vector3(8 / 16.0, 1 / 16.0, 0.8 / 16.0), + new Vector4(16 / 16.0, 0 / 16.0, 16 / 16.0, 0 / 16.0) + )) }; static final Quad[][] orientedQuads = new Quad[4][]; + private static final Transform[] slotItemTransforms = new Transform[]{ + Transform.NONE + .translate(-.5, 0, -.5) + .scale(0.38) + .translate(13 / 16., 7 / 16., 13 / 16.), + Transform.NONE + .translate(-.5, 0, -.5) + .rotateY(Math.toRadians(90)) + .scale(0.38).translate(13 / 16., 7 / 16., 3 / 16.), + Transform.NONE + .translate(-.5, 0, -.5) + .rotateY(Math.toRadians(180)) + .scale(0.38).translate(3 / 16., 7 / 16., 3 / 16.), + Transform.NONE + .translate(-.5, 0, -.5) + .rotateY(Math.toRadians(270)) + .scale(0.38).translate(3 / 16., 7 / 16., 13 / 16.) + }; + static { orientedQuads[0] = quads; orientedQuads[1] = Model.rotateY(orientedQuads[0]); @@ -258,13 +284,15 @@ private static Quad rotateFire(Quad quad) { return new Quad(quad, Transform.NONE.rotateY(Math.toRadians(45))); } - private static final Quad[] fireQuads = new Quad[] { - quads[quads.length-4], quads[quads.length-3], - quads[quads.length-2], quads[quads.length-1], + private static final Quad[] fireQuads = new Quad[]{ + quads[quads.length - 4], quads[quads.length - 3], + quads[quads.length - 2], quads[quads.length - 1], }; + public static int faceCount() { - return fireQuads.length; + return fireQuads.length; } + public static void sample(int face, Vector3 loc, Random rand) { fireQuads[face].sample(loc, rand); } @@ -280,13 +308,15 @@ public static double surfaceArea(int face) { private final String facing; private final boolean isLit; private final Block block; + private final String[] slots; - public Campfire(Campfire.Kind kind, Vector3 position, String facing, boolean lit, Block block) { + public Campfire(Campfire.Kind kind, Vector3 position, String facing, boolean lit, Block block, String slot1, String slot2, String slot3, String slot4) { super(position); this.kind = kind; this.facing = facing; this.isLit = lit; this.block = block; + slots = new String[]{slot1, slot2, slot3, slot4}; } public Campfire(JsonObject json) { @@ -295,16 +325,23 @@ public Campfire(JsonObject json) { this.facing = json.get("facing").stringValue("north"); this.isLit = json.get("lit").boolValue(true); this.block = null; + this.slots = new String[4]; + JsonArray items = json.get("items").asArray(); + for (int slot = 0; slot < 4; slot++) { + if (items.size() > slot) { + this.slots[slot] = items.get(slot).stringValue(""); + } + } } @Override public Collection primitives(Vector3 offset) { Collection faces = new LinkedList<>(); Transform transform = Transform.NONE - .translate(position.x + offset.x, position.y + offset.y, position.z + offset.z); + .translate(position.x + offset.x, position.y + offset.y, position.z + offset.z); int facing = getOrientationIndex(this.facing); Texture[] textures = - isLit ? (kind == Kind.SOUL_CAMPFIRE ? texLitSoulCampfire : texLitCampfire) : tex; + isLit ? (kind == Kind.SOUL_CAMPFIRE ? texLitSoulCampfire : texLitCampfire) : tex; for (int i = 0; i < orientedQuads[facing].length - 4; i++) { Material material = new TextureMaterial(textures[i]); orientedQuads[facing][i].addTriangles(faces, material, transform); @@ -314,6 +351,33 @@ public Collection primitives(Vector3 offset) { orientedQuads[facing][i].addTriangles(faces, kind.flameMaterial, transform); } } + + for (int slot = 0; slot < 4; slot++) { + if (slots[slot] == null) { + continue; + } + String[] namespaceAndId = slots[slot].split(":"); + if (namespaceAndId.length == 2) { + String textureId = "assets/" + namespaceAndId[0] + "/textures/item/" + namespaceAndId[1]; + Texture texture = TextureCache.get(textureId); + if (texture == null) { + texture = new Texture(); + TextureLoader loader = new SimpleTexture(textureId, texture); + if (!ResourcePackLoader.loadResources( + ResourcePackTextureLoader.singletonLoader(textureId, loader)) + ) { + Log.warnf("Failed to load texture: %s", textureId); + } + TextureCache.put(textureId, texture); + } + Quad[] quads = GeneratedItemModel.generateItemModelQuads(texture); + Material textureMaterial = new TextureMaterial(texture); + for (Quad quad : quads) { + quad.addTriangles(faces, textureMaterial, slotItemTransforms[slot].chain(transform)); + } + } + } + return faces; } @@ -325,6 +389,12 @@ public JsonValue toJson() { json.add("position", position.toJson()); json.add("facing", facing); json.add("lit", isLit); + JsonArray items = new JsonArray(); + items.add(slots[0]); + items.add(slots[1]); + items.add(slots[2]); + items.add(slots[3]); + json.add("items", items); return json; } @@ -335,31 +405,31 @@ public static Entity fromJson(JsonObject json) { private static int getOrientationIndex(String facing) { switch (facing) { case "north": - return 0; + return 0; case "east": - return 1; + return 1; case "south": - return 2; + return 2; case "west": - return 3; + return 3; default: - return 0; + return 0; } } @Override public Grid.EmitterPosition[] getEmitterPosition() { - if (block == null) { - Log.warn("Attempted to build emitter grid from unassociated campfire entity."); - return new Grid.EmitterPosition[0]; - } + if (block == null) { + Log.warn("Attempted to build emitter grid from unassociated campfire entity."); + return new Grid.EmitterPosition[0]; + } - if (isLit) { - Grid.EmitterPosition[] pos = new Grid.EmitterPosition[1]; - pos[0] = new Grid.EmitterPosition((int) position.x, (int) position.y, (int) position.z, block); - return pos; - } else { - return new Grid.EmitterPosition[0]; - } + if (isLit) { + Grid.EmitterPosition[] pos = new Grid.EmitterPosition[1]; + pos[0] = new Grid.EmitterPosition((int) position.x, (int) position.y, (int) position.z, block); + return pos; + } else { + return new Grid.EmitterPosition[0]; + } } }