Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 55 additions & 24 deletions chunky/src/java/se/llbit/chunky/model/AABBModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,76 @@
import se.llbit.math.Vector3;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Random;

/**
* A block model that is made out of textured AABBs.
* A block model that is made out of textured axis-aligned bounding boxes (AABBs).
*/
@PluginApi
public abstract class AABBModel implements BlockModel {

/**
* Different UV mapping methods.
* - None: No change in mapping
* - ROTATE_90: Rotate 90 degrees clockwise
* - ROTATE_180: Rotate 180 degrees
* - ROTATE_270: Rotate 270 degrees clockwise (90 degrees counterclockwise)
* - FLIP_U: Flip along the X axis (u = 1 - u)
* - FLIP_V: Flip along the Y axis (v = 1 - v)
* <p>
* Note: a value of {@code null} is equivalent to {@code NONE}
*/
public enum UVMapping {
/**
* No change in mapping.
*/
NONE,
/**
* Rotate by 90 degrees clockwise.
*/
ROTATE_90,
/**
* Rotate by 180 degrees.
*/
ROTATE_180,
/**
* Rotate 270 degrees clockwise (90 degrees counter clockwise).
*/
ROTATE_270,
/**
* Mirror horizontally (u = 1 - u).
*/
FLIP_U,
/**
* Mirror vertically (v = 1 - v).
*/
FLIP_V
}

/**
* Get the boxes for this model.
*
* @return An array of boxes.
*/
@PluginApi
public abstract AABB[] getBoxes();

/**
* Get textures for the boxes.
*
* @return An array of textures for the boxes, each in north, east, south, west, top, bottom order.
*/
@PluginApi
public abstract Texture[][] getTextures();

/**
* Get tints for the boxes. If an entry is <code>null</code> or this method returns <code>null</code>, it is equivalent to {@link Tint#NONE}.
*
* @return An array of tints for the boxes, each in north, east, south, west, top, bottom order.
*/
@PluginApi
public Tint[][] getTints() {
return null;
}

/**
* Get UV mappings for the boxes. If an entry is <code>null</code> or this method returns <code>null</code>, it is equivalent to {@link UVMapping#NONE}.
*
* @return An array of UV mappings for the boxes, each in north, east, south, west, top, bottom order.
*/
@PluginApi
public UVMapping[][] getUVMapping() {
return null;
Expand Down Expand Up @@ -81,45 +110,47 @@ public boolean intersect(Ray ray, Scene scene) {
ray.t = Double.POSITIVE_INFINITY;
for (int i = 0; i < boxes.length; ++i) {
if (boxes[i].intersect(ray)) {
Texture[] texturesBox = textures[i];
Tint[] tintedFacesBox = tintedFaces != null ? tintedFaces[i] : null;
UVMapping[] mappingBox = mapping != null ? mapping[i] : null;
Vector3 n = ray.getNormal();
if (n.y > 0) { // top
ray.v = 1 - ray.v;
if (intersectFace(ray, scene, textures[i][4],
mapping != null ? mapping[i][4] : null
if (intersectFace(ray, texturesBox[4],
mappingBox != null ? mappingBox[4] : null
)) {
tint = tintedFacesBox != null ? tintedFacesBox[4] : Tint.NONE;
hit = true;
}
} else if (n.y < 0) { // bottom
if (intersectFace(ray, scene, textures[i][5],
mapping != null ? mapping[i][5] : null)) {
if (intersectFace(ray, texturesBox[5],
mappingBox != null ? mappingBox[5] : null)) {
hit = true;
tint = tintedFacesBox != null ? tintedFacesBox[5] : Tint.NONE;
}
} else if (n.z < 0) { // north
if (intersectFace(ray, scene, textures[i][0],
mapping != null ? mapping[i][0] : null
if (intersectFace(ray, texturesBox[0],
mappingBox != null ? mappingBox[0] : null
)) {
hit = true;
tint = tintedFacesBox != null ? tintedFacesBox[0] : Tint.NONE;
}
} else if (n.z > 0) { // south
if (intersectFace(ray, scene, textures[i][2],
mapping != null ? mapping[i][2] : null
if (intersectFace(ray, texturesBox[2],
mappingBox != null ? mappingBox[2] : null
)) {
hit = true;
tint = tintedFacesBox != null ? tintedFacesBox[2] : Tint.NONE;
}
} else if (n.x < 0) { // west
if (intersectFace(ray, scene, textures[i][3],
mapping != null ? mapping[i][3] : null)) {
if (intersectFace(ray, texturesBox[3],
mappingBox != null ? mappingBox[3] : null)) {
hit = true;
tint = tintedFacesBox != null ? tintedFacesBox[3] : Tint.NONE;
}
} else if (n.x > 0) { // east
if (intersectFace(ray, scene, textures[i][1],
mapping != null ? mapping[i][1] : null)) {
if (intersectFace(ray, texturesBox[1],
mappingBox != null ? mappingBox[1] : null)) {
hit = true;
tint = tintedFacesBox != null ? tintedFacesBox[1] : Tint.NONE;
}
Expand All @@ -141,7 +172,7 @@ public boolean intersect(Ray ray, Scene scene) {
return hit;
}

private boolean intersectFace(Ray ray, Scene scene, Texture texture, UVMapping mapping) {
private boolean intersectFace(Ray ray, Texture texture, UVMapping mapping) {
// This is the method that handles intersecting faces of all AABB-based models.
// Do normal mapping, parallax occlusion mapping, specular maps and all the good stuff here!

Expand Down Expand Up @@ -186,7 +217,7 @@ private boolean intersectFace(Ray ray, Scene scene, Texture texture, UVMapping m
@Override
public boolean isBiomeDependant() {
Tint[][] tints = getTints();
if(tints == null)
if (tints == null)
return false;

return Arrays.stream(tints)
Expand Down