Merge branch 'master' into mc/1.12

This commit is contained in:
Blue (Lukas Rieger) 2020-01-19 12:13:30 +01:00
commit 0425243a28
4 changed files with 33 additions and 242 deletions

View File

@ -52,8 +52,8 @@ public HiresModelRenderer(ResourcePack resourcePack, RenderSettings renderSettin
} }
public HiresModel render(WorldTile tile, AABB region) { public HiresModel render(WorldTile tile, AABB region) {
Vector3i modelMin = region.getMin().toInt(); Vector3i modelMin = region.getMin();
Vector3i modelMax = region.getMax().toInt(); Vector3i modelMax = region.getMax();
Vector3i min = modelMin.max(renderSettings.getMin()); Vector3i min = modelMin.max(renderSettings.getMin());
Vector3i max = modelMax.min(renderSettings.getMax()); Vector3i max = modelMax.min(renderSettings.getMax());

View File

@ -24,42 +24,28 @@
*/ */
package de.bluecolored.bluemap.core.util; package de.bluecolored.bluemap.core.util;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Optional; import com.flowpowered.math.GenericMath;
import com.flowpowered.math.vector.Vector3d; import com.flowpowered.math.vector.Vector3d;
import com.flowpowered.math.vector.Vector3i; import com.flowpowered.math.vector.Vector3i;
/** /**
* An axis aligned bounding box. That is, an un-rotated cuboid. * An axis aligned bounding box. That is, an un-rotated cuboid.
* It is represented by its minimum and maximum corners. * It is represented by its minimum and maximum corners.
* *
* <p>The box will never be degenerate: the corners are always not equal and * Using integers, the box has a minimum size of 1 in each direction.
* respect the minimum and maximum properties.</p>
* *
* <p>This class is immutable, all objects returned are either new instances or * <p>This class is immutable, all objects returned are either new instances or
* itself.</p> * itself.</p>
*/ */
public class AABB { public class AABB {
private final Vector3d min; private final Vector3i min;
private final Vector3d max; private final Vector3i max;
private Vector3d size = null; private Vector3i size = null;
private Vector3d center = null; private Vector3d center = null;
/**
* Constructs a new bounding box from two opposite corners.
* Fails the resulting box would be degenerate (a dimension is 0).
*
* @param firstCorner The first corner
* @param secondCorner The second corner
*/
public AABB(Vector3i firstCorner, Vector3i secondCorner) {
this(checkNotNull(firstCorner, "firstCorner").toDouble(), checkNotNull(secondCorner, "secondCorner").toDouble());
}
/** /**
* Constructs a new bounding box from two opposite corners. * Constructs a new bounding box from two opposite corners.
* Fails the resulting box would be degenerate (a dimension is 0). * Fails the resulting box would be degenerate (a dimension is 0).
@ -71,8 +57,8 @@ public AABB(Vector3i firstCorner, Vector3i secondCorner) {
* @param y2 The second corner y coordinate * @param y2 The second corner y coordinate
* @param z2 The second corner z coordinate * @param z2 The second corner z coordinate
*/ */
public AABB(double x1, double y1, double z1, double x2, double y2, double z2) { public AABB(int x1, int y1, int z1, int x2, int y2, int z2) {
this(new Vector3d(x1, y1, z1), new Vector3d(x2, y2, z2)); this(new Vector3i(x1, y1, z1), new Vector3i(x2, y2, z2));
} }
/** /**
@ -82,14 +68,11 @@ public AABB(double x1, double y1, double z1, double x2, double y2, double z2) {
* @param firstCorner The first corner * @param firstCorner The first corner
* @param secondCorner The second corner * @param secondCorner The second corner
*/ */
public AABB(Vector3d firstCorner, Vector3d secondCorner) { public AABB(Vector3i firstCorner, Vector3i secondCorner) {
checkNotNull(firstCorner, "firstCorner"); checkNotNull(firstCorner, "firstCorner");
checkNotNull(secondCorner, "secondCorner"); checkNotNull(secondCorner, "secondCorner");
this.min = firstCorner.min(secondCorner); this.min = firstCorner.min(secondCorner);
this.max = firstCorner.max(secondCorner); this.max = firstCorner.max(secondCorner);
checkArgument(this.min.getX() != this.max.getX(), "The box is degenerate on x");
checkArgument(this.min.getY() != this.max.getY(), "The box is degenerate on y");
checkArgument(this.min.getZ() != this.max.getZ(), "The box is degenerate on z");
} }
/** /**
@ -97,7 +80,7 @@ public AABB(Vector3d firstCorner, Vector3d secondCorner) {
* *
* @return The minimum corner * @return The minimum corner
*/ */
public Vector3d getMin() { public Vector3i getMin() {
return this.min; return this.min;
} }
@ -106,7 +89,7 @@ public Vector3d getMin() {
* *
* @return The maximum corner * @return The maximum corner
*/ */
public Vector3d getMax() { public Vector3i getMax() {
return this.max; return this.max;
} }
@ -117,7 +100,7 @@ public Vector3d getMax() {
*/ */
public Vector3d getCenter() { public Vector3d getCenter() {
if (this.center == null) { if (this.center == null) {
this.center = this.min.add(getSize().div(2)); this.center = this.min.toDouble().add(getSize().toDouble().div(2));
} }
return this.center; return this.center;
} }
@ -127,9 +110,9 @@ public Vector3d getCenter() {
* *
* @return The size * @return The size
*/ */
public Vector3d getSize() { public Vector3i getSize() {
if (this.size == null) { if (this.size == null) {
this.size = this.max.sub(this.min); this.size = this.max.sub(this.min).add(Vector3i.ONE);
} }
return this.size; return this.size;
} }
@ -165,6 +148,18 @@ public boolean contains(Vector3d point) {
* @return Whether or not the box contains the point * @return Whether or not the box contains the point
*/ */
public boolean contains(double x, double y, double z) { public boolean contains(double x, double y, double z) {
return contains(GenericMath.floor(x), GenericMath.floor(y), GenericMath.floor(z));
}
/**
* Checks if the bounding box contains a point.
*
* @param x The x coordinate of the point
* @param y The y coordinate of the point
* @param z The z coordinate of the point
* @return Whether or not the box contains the point
*/
public boolean contains(int x, int y, int z) {
return this.min.getX() <= x && this.max.getX() >= x return this.min.getX() <= x && this.max.getX() >= x
&& this.min.getY() <= y && this.max.getY() >= y && this.min.getY() <= y && this.max.getY() >= y
&& this.min.getZ() <= z && this.max.getZ() >= z; && this.min.getZ() <= z && this.max.getZ() >= z;
@ -183,156 +178,6 @@ public boolean intersects(AABB other) {
&& this.max.getZ() >= other.getMin().getZ() && other.getMax().getZ() >= this.min.getZ(); && this.max.getZ() >= other.getMin().getZ() && other.getMax().getZ() >= this.min.getZ();
} }
/**
* Tests for intersection between the box and a ray defined by a starting
* point and a direction.
*
* @param start The starting point of the ray
* @param direction The direction of the ray
* @return An intersection point, if any
*/
public Optional<IntersectionPoint> intersects(Vector3d start, Vector3d direction) {
checkNotNull(start, "start");
checkNotNull(direction, "direction");
// Adapted from: https://github.com/flow/react/blob/develop/src/main/java/com/flowpowered/react/collision/RayCaster.java#L156
// The box is interpreted as 6 infinite perpendicular places, one for each face (being expanded infinitely)
// "t" variables are multipliers: start + direction * t gives the intersection point
// Find the intersections on the -x and +x planes, oriented by direction
final double txMin;
final double txMax;
final Vector3d xNormal;
if (Math.copySign(1, direction.getX()) > 0) {
txMin = (this.min.getX() - start.getX()) / direction.getX();
txMax = (this.max.getX() - start.getX()) / direction.getX();
xNormal = Vector3d.UNIT_X;
} else {
txMin = (this.max.getX() - start.getX()) / direction.getX();
txMax = (this.min.getX() - start.getX()) / direction.getX();
xNormal = Vector3d.UNIT_X.negate();
}
// Find the intersections on the -y and +y planes, oriented by direction
final double tyMin;
final double tyMax;
final Vector3d yNormal;
if (Math.copySign(1, direction.getY()) > 0) {
tyMin = (this.min.getY() - start.getY()) / direction.getY();
tyMax = (this.max.getY() - start.getY()) / direction.getY();
yNormal = Vector3d.UNIT_Y;
} else {
tyMin = (this.max.getY() - start.getY()) / direction.getY();
tyMax = (this.min.getY() - start.getY()) / direction.getY();
yNormal = Vector3d.UNIT_Y.negate();
}
// The ray should intersect the -x plane before the +y plane and intersect
// the -y plane before the +x plane, else it is outside the box
if (txMin > tyMax || txMax < tyMin) {
return Optional.empty();
}
// Keep track of the intersection normal which also helps with floating point errors
Vector3d normalMax;
Vector3d normalMin;
// The ray intersects only the furthest min plane on the box and only the closest
// max plane on the box
double tMin;
if (tyMin == txMin) {
tMin = tyMin;
normalMin = xNormal.negate().sub(yNormal);
} else if (tyMin > txMin) {
tMin = tyMin;
normalMin = yNormal.negate();
} else {
tMin = txMin;
normalMin = xNormal.negate();
}
double tMax;
if (tyMax == txMax) {
tMax = tyMax;
normalMax = xNormal.add(yNormal);
} else if (tyMax < txMax) {
tMax = tyMax;
normalMax = yNormal;
} else {
tMax = txMax;
normalMax = xNormal;
}
// Find the intersections on the -z and +z planes, oriented by direction
final double tzMin;
final double tzMax;
final Vector3d zNormal;
if (Math.copySign(1, direction.getZ()) > 0) {
tzMin = (this.min.getZ() - start.getZ()) / direction.getZ();
tzMax = (this.max.getZ() - start.getZ()) / direction.getZ();
zNormal = Vector3d.UNIT_Z;
} else {
tzMin = (this.max.getZ() - start.getZ()) / direction.getZ();
tzMax = (this.min.getZ() - start.getZ()) / direction.getZ();
zNormal = Vector3d.UNIT_Z.negate();
}
// The ray intersects only the furthest min plane on the box and only the closest
// max plane on the box
if (tMin > tzMax || tMax < tzMin) {
return Optional.empty();
}
// The ray should intersect the closest plane outside first and the furthest
// plane outside last
if (tzMin == tMin) {
normalMin = normalMin.sub(zNormal);
} else if (tzMin > tMin) {
tMin = tzMin;
normalMin = zNormal.negate();
}
if (tzMax == tMax) {
normalMax = normalMax.add(zNormal);
} else if (tzMax < tMax) {
tMax = tzMax;
normalMax = zNormal;
}
// Both intersection points are behind the start, there are no intersections
if (tMax < 0) {
return Optional.empty();
}
// Find the final intersection multiplier and normal
final double t;
Vector3d normal;
if (tMin < 0) {
// Only the furthest intersection is after the start, so use it
t = tMax;
normal = normalMax;
} else {
// Both are after the start, use the closest one
t = tMin;
normal = normalMin;
}
normal = normal.normalize();
// To avoid rounding point errors leaving the intersection point just off the plane
// we check the normal to use the actual plane value from the box coordinates
final double x;
final double y;
final double z;
if (normal.getX() > 0) {
x = this.max.getX();
} else if (normal.getX() < 0) {
x = this.min.getX();
} else {
x = direction.getX() * t + start.getX();
}
if (normal.getY() > 0) {
y = this.max.getY();
} else if (normal.getY() < 0) {
y = this.min.getY();
} else {
y = direction.getY() * t + start.getY();
}
if (normal.getZ() > 0) {
z = this.max.getZ();
} else if (normal.getZ() < 0) {
z = this.min.getZ();
} else {
z = direction.getZ() * t + start.getZ();
}
return Optional.of(new IntersectionPoint(new Vector3d(x, y, z), normal));
}
/** /**
* Offsets this bounding box by a given amount and returns a new box. * Offsets this bounding box by a given amount and returns a new box.
* *
@ -344,17 +189,6 @@ public AABB offset(Vector3i offset) {
return offset(offset.getX(), offset.getY(), offset.getZ()); return offset(offset.getX(), offset.getY(), offset.getZ());
} }
/**
* Offsets this bounding box by a given amount and returns a new box.
*
* @param offset The offset to apply
* @return The new offset box
*/
public AABB offset(Vector3d offset) {
checkNotNull(offset, "offset");
return offset(offset.getX(), offset.getY(), offset.getZ());
}
/** /**
* Offsets this bounding box by a given amount and returns a new box. * Offsets this bounding box by a given amount and returns a new box.
* *
@ -363,53 +197,10 @@ public AABB offset(Vector3d offset) {
* @param z The amount of offset for the z coordinate * @param z The amount of offset for the z coordinate
* @return The new offset box * @return The new offset box
*/ */
public AABB offset(double x, double y, double z) { public AABB offset(int x, int y, int z) {
return new AABB(this.min.add(x, y, z), this.max.add(x, y, z)); return new AABB(this.min.add(x, y, z), this.max.add(x, y, z));
} }
/**
* Expands this bounding box by a given amount in both directions and
* returns a new box. The expansion is applied half and half to the
* minimum and maximum corners.
*
* @param amount The amount of expansion to apply
* @return The new expanded box
*/
public AABB expand(Vector3i amount) {
checkNotNull(amount, "amount");
return expand(amount.getX(), amount.getY(), amount.getZ());
}
/**
* Expands this bounding box by a given amount in both directions and
* returns a new box. The expansion is applied half and half to the
* minimum and maximum corners.
*
* @param amount The amount of expansion to apply
* @return The new expanded box
*/
public AABB expand(Vector3d amount) {
checkNotNull(amount, "amount");
return expand(amount.getX(), amount.getY(), amount.getZ());
}
/**
* Expands this bounding box by a given amount in both directions and
* returns a new box. The expansion is applied half and half to the
* minimum and maximum corners.
*
* @param x The amount of expansion for the x coordinate
* @param y The amount of expansion for the y coordinate
* @param z The amount of expansion for the z coordinate
* @return The new expanded box
*/
public AABB expand(double x, double y, double z) {
x /= 2;
y /= 2;
z /= 2;
return new AABB(this.min.sub(x, y, z), this.max.add(x, y, z));
}
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
if (this == other) { if (this == other) {

View File

@ -132,7 +132,7 @@ public boolean isChunkGenerated(Vector2i chunkPos) throws IOException {
@Override @Override
public boolean isAreaGenerated(AABB area) throws IOException { public boolean isAreaGenerated(AABB area) throws IOException {
if (!isInside(blockPosToChunkPos(area.getMin().toInt())) && !isInside(blockPosToChunkPos(area.getMax().toInt()))) return false; if (!isInside(blockPosToChunkPos(area.getMin())) && !isInside(blockPosToChunkPos(area.getMax()))) return false;
return world.isAreaGenerated(area); return world.isAreaGenerated(area);
} }

View File

@ -94,7 +94,7 @@ public default Collection<Vector2i> getChunkList(){
* @throws IOException * @throws IOException
*/ */
public default boolean isAreaGenerated(AABB area) throws IOException { public default boolean isAreaGenerated(AABB area) throws IOException {
return isAreaGenerated(area.getMin().toInt(), area.getMax().toInt()); return isAreaGenerated(area.getMin(), area.getMax());
} }
/** /**