package codechicken.lib.vec;
import codechicken.lib.math.MathHelper;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
public class Rotation extends Transformation {
/**
* Clockwise pi/2 about y looking down
*/
public static Transformation[] quarterRotations = new Transformation[] { new RedundantTransformation(), new VariableTransformation(new Matrix4(0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1)) {
@Override
public void apply(Vector3 vec) {
double d1 = vec.x;
double d2 = vec.z;
vec.x = -d2;
vec.z = d1;
}
@Override
public Transformation inverse() {
return quarterRotations[3];
}
}, new VariableTransformation(new Matrix4(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1)) {
@Override
public void apply(Vector3 vec) {
vec.x = -vec.x;
vec.z = -vec.z;
}
@Override
public Transformation inverse() {
return this;
}
}, new VariableTransformation(new Matrix4(0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1)) {
@Override
public void apply(Vector3 vec) {
double d1 = vec.x;
double d2 = vec.z;
vec.x = d2;
vec.z = -d1;
}
@Override
public Transformation inverse() {
return quarterRotations[1];
}
} };
public static Transformation[] sideRotations = new Transformation[] { new RedundantTransformation(), new VariableTransformation(new Matrix4(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1)) {
@Override
public void apply(Vector3 vec) {
vec.y = -vec.y;
vec.z = -vec.z;
}
@Override
public Transformation inverse() {
return this;
}
}, new VariableTransformation(new Matrix4(1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1)) {
@Override
public void apply(Vector3 vec) {
double d1 = vec.y;
double d2 = vec.z;
vec.y = -d2;
vec.z = d1;
}
@Override
public Transformation inverse() {
return sideRotations[3];
}
}, new VariableTransformation(new Matrix4(1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1)) {
@Override
public void apply(Vector3 vec) {
double d1 = vec.y;
double d2 = vec.z;
vec.y = d2;
vec.z = -d1;
}
@Override
public Transformation inverse() {
return sideRotations[2];
}
}, new VariableTransformation(new Matrix4(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)) {
@Override
public void apply(Vector3 vec) {
double d0 = vec.x;
double d1 = vec.y;
vec.x = d1;
vec.y = -d0;
}
@Override
public Transformation inverse() {
return sideRotations[5];
}
}, new VariableTransformation(new Matrix4(0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)) {
@Override
public void apply(Vector3 vec) {
double d0 = vec.x;
double d1 = vec.y;
vec.x = -d1;
vec.y = d0;
}
@Override
public Transformation inverse() {
return sideRotations[4];
}
} };
public static Vector3[] axes = new Vector3[] { new Vector3(0, -1, 0), new Vector3(0, 1, 0), new Vector3(0, 0, -1), new Vector3(0, 0, 1), new Vector3(-1, 0, 0), new Vector3(1, 0, 0) };
public static int[] sideRotMap = new int[] { 3, 4, 2, 5, 3, 5, 2, 4, 1, 5, 0, 4, 1, 4, 0, 5, 1, 2, 0, 3, 1, 3, 0, 2 };
public static int[] rotSideMap = new int[] { -1, -1, 2, 0, 1, 3, -1, -1, 2, 0, 3, 1, 2, 0, -1, -1, 3, 1, 2, 0, -1, -1, 1, 3, 2, 0, 1, 3, -1, -1, 2, 0, 3, 1, -1, -1 };
/**
* Rotate pi/2 * this offset for [side] about y axis before rotating to the side for the rotation indicies to line up
*/
public static int[] sideRotOffsets = new int[] { 0, 2, 2, 0, 1, 3 };
public static int rotateSide(int s, int r) {
return sideRotMap[s << 2 | r];
}
/**
* Reverse of rotateSide
*/
public static int rotationTo(int s1, int s2) {
if ((s1 & 6) == (s2 & 6)) {
throw new IllegalArgumentException("Faces " + s1 + " and " + s2 + " are opposites");
}
return rotSideMap[s1 * 6 + s2];
}
/**
* @param player The placing player, used for obtaining the look vector
* @param side The side of the block being placed on
* @return The rotation for the face == side^1
*/
public static int getSidedRotation(EntityPlayer player, int side) {
Vector3 look = new Vector3(player.getLook(1));
double max = 0;
int maxr = 0;
for (int r = 0; r < 4; r++) {
Vector3 axis = Rotation.axes[rotateSide(side ^ 1, r)];
double d = look.scalarProject(axis);
if (d > max) {
max = d;
maxr = r;
}
}
return maxr;
}
/**
* @return The rotation quat for side 0 and rotation 0 to side s with rotation r
*/
public static Transformation sideOrientation(int s, int r) {
return quarterRotations[(r + sideRotOffsets[s]) % 4].with(sideRotations[s]);
}
/**
* @param entity The placing entity, used for obtaining the look vector
* @return The side towards which the entity is most directly looking.
*/
public static int getSideFromLookAngle(EntityLivingBase entity) {
Vector3 look = new Vector3(entity.getLook(1));
double max = 0;
int maxs = 0;
for (int s = 0; s < 6; s++) {
double d = look.scalarProject(axes[s]);
if (d > max) {
max = d;
maxs = s;
}
}
return maxs;
}
public double angle;
public Vector3 axis;
private Quat quat;
public Rotation(double angle, Vector3 axis) {
this.angle = angle;
this.axis = axis;
}
public Rotation(double angle, double x, double y, double z) {
this(angle, new Vector3(x, y, z));
}
public Rotation(Quat quat) {
this.quat = quat;
angle = Math.acos(quat.s) * 2;
if (angle == 0) {
axis = new Vector3(0, 1, 0);
} else {
double sa = Math.sin(angle * 0.5);
axis = new Vector3(quat.x / sa, quat.y / sa, quat.z / sa);
}
}
@Override
public void apply(Vector3 vec) {
if (quat == null) {
quat = Quat.aroundAxis(axis, angle);
}
vec.rotate(quat);
}
@Override
public void applyN(Vector3 normal) {
apply(normal);
}
@Override
public void apply(Matrix4 mat) {
mat.rotate(angle, axis);
}
public Quat toQuat() {
if (quat == null) {
quat = Quat.aroundAxis(axis, angle);
}
return quat;
}
@Override
@SideOnly(Side.CLIENT)
public void glApply() {
GlStateManager.rotate((float) (angle * MathHelper.todeg), (float) axis.x, (float) axis.y, (float) axis.z);
}
@Override
public Transformation inverse() {
return new Rotation(-angle, axis);
}
@Override
public Transformation merge(Transformation next) {
if (next instanceof Rotation) {
Rotation r = (Rotation) next;
if (r.axis.equalsT(axis)) {
return new Rotation(angle + r.angle, axis);
}
return new Rotation(toQuat().copy().multiply(r.toQuat()));
}
return null;
}
@Override
public boolean isRedundant() {
return MathHelper.between(-1E-5, angle, 1E-5);
}
@Override
public String toString() {
MathContext cont = new MathContext(4, RoundingMode.HALF_UP);
return "Rotation(" + new BigDecimal(angle, cont) + ", " + new BigDecimal(axis.x, cont) + ", " +
new BigDecimal(axis.y, cont) + ", " + new BigDecimal(axis.z, cont) + ")";
}
}