package openmods.gui.misc;
import com.google.common.collect.Maps;
import java.util.Map;
import net.minecraft.util.Vec3;
import net.minecraftforge.common.util.ForgeDirection;
import openmods.utils.render.ProjectionHelper;
import org.lwjgl.input.Mouse;
public class SidePicker {
private static final ProjectionHelper projectionHelper = new ProjectionHelper();
public enum Side {
XNeg,
XPos,
YNeg,
YPos,
ZNeg,
ZPos;
public static Side fromForgeDirection(ForgeDirection dir) {
switch (dir) {
case WEST:
return XNeg;
case EAST:
return XPos;
case DOWN:
return YNeg;
case UP:
return YPos;
case NORTH:
return ZNeg;
case SOUTH:
return ZPos;
default:
break;
}
return null;
}
public ForgeDirection toForgeDirection() {
switch (this) {
case XNeg:
return ForgeDirection.WEST;
case XPos:
return ForgeDirection.EAST;
case YNeg:
return ForgeDirection.DOWN;
case YPos:
return ForgeDirection.UP;
case ZNeg:
return ForgeDirection.NORTH;
case ZPos:
return ForgeDirection.SOUTH;
default:
return ForgeDirection.UNKNOWN;
}
}
}
public static class HitCoord {
public final Side side;
public final Vec3 coord;
public HitCoord(Side side, Vec3 coord) {
this.side = side;
this.coord = coord;
}
}
private final double negX, negY, negZ;
private final double posX, posY, posZ;
public SidePicker(double negX, double negY, double negZ, double posX, double posY, double posZ) {
this.negX = negX;
this.negY = negY;
this.negZ = negZ;
this.posX = posX;
this.posY = posY;
this.posZ = posZ;
}
public SidePicker(double halfSize) {
negX = negY = negZ = -halfSize;
posX = posY = posZ = +halfSize;
}
private static Vec3 getMouseVector(float z) {
return projectionHelper.unproject(Mouse.getX(), Mouse.getY(), z);
}
private Vec3 calculateXPoint(Vec3 near, Vec3 diff, double x) {
double p = (x - near.xCoord) / diff.xCoord;
double y = near.yCoord + diff.yCoord * p;
double z = near.zCoord + diff.zCoord * p;
if (negY <= y && y <= posY && negZ <= z && z <= posZ) return Vec3.createVectorHelper(x, y, z);
return null;
}
private Vec3 calculateYPoint(Vec3 near, Vec3 diff, double y) {
double p = (y - near.yCoord) / diff.yCoord;
double x = near.xCoord + diff.xCoord * p;
double z = near.zCoord + diff.zCoord * p;
if (negX <= x && x <= posX && negZ <= z && z <= posZ) return Vec3.createVectorHelper(x, y, z);
return null;
}
private Vec3 calculateZPoint(Vec3 near, Vec3 diff, double z) {
double p = (z - near.zCoord) / diff.zCoord;
double x = near.xCoord + diff.xCoord * p;
double y = near.yCoord + diff.yCoord * p;
if (negX <= x && x <= posX && negY <= y && y <= posY) return Vec3.createVectorHelper(x, y, z);
return null;
}
private static void addPoint(Map<Side, Vec3> map, Side side, Vec3 value) {
if (value != null) map.put(side, value);
}
private Map<Side, Vec3> calculateHitPoints(Vec3 near, Vec3 far) {
Vec3 diff = far.subtract(near);
Map<Side, Vec3> result = Maps.newEnumMap(Side.class);
addPoint(result, Side.XNeg, calculateXPoint(near, diff, negX));
addPoint(result, Side.XPos, calculateXPoint(near, diff, posX));
addPoint(result, Side.YNeg, calculateYPoint(near, diff, negY));
addPoint(result, Side.YPos, calculateYPoint(near, diff, posY));
addPoint(result, Side.ZNeg, calculateZPoint(near, diff, negZ));
addPoint(result, Side.ZPos, calculateZPoint(near, diff, posZ));
return result;
}
public Map<Side, Vec3> calculateMouseHits() {
projectionHelper.updateMatrices();
Vec3 near = getMouseVector(0);
Vec3 far = getMouseVector(1);
return calculateHitPoints(near, far);
}
public HitCoord getNearestHit() {
projectionHelper.updateMatrices();
Vec3 near = getMouseVector(0);
Vec3 far = getMouseVector(1);
Map<Side, Vec3> hits = calculateHitPoints(near, far);
if (hits.isEmpty()) return null;
Side minSide = null;
double minDist = Double.MAX_VALUE;
// yeah, I know there are two entries max, but... meh
for (Map.Entry<Side, Vec3> e : hits.entrySet()) {
double dist = e.getValue().subtract(near).lengthVector();
if (dist < minDist) {
minDist = dist;
minSide = e.getKey();
}
}
if (minSide == null) return null; // !?
return new HitCoord(minSide, hits.get(minSide));
}
}