2020-07-22 06:25:47 +01:00
|
|
|
package com.mojang.math;
|
|
|
|
|
|
|
|
import net.minecraft.Util;
|
|
|
|
import java.util.Objects;
|
|
|
|
import org.apache.commons.lang3.tuple.Triple;
|
|
|
|
import com.mojang.datafixers.util.Pair;
|
|
|
|
import javax.annotation.Nullable;
|
|
|
|
|
|
|
|
public final class Transformation {
|
|
|
|
private final Matrix4f matrix;
|
|
|
|
private boolean decomposed;
|
|
|
|
@Nullable
|
|
|
|
private Vector3f translation;
|
|
|
|
@Nullable
|
|
|
|
private Quaternion leftRotation;
|
|
|
|
@Nullable
|
|
|
|
private Vector3f scale;
|
|
|
|
@Nullable
|
|
|
|
private Quaternion rightRotation;
|
|
|
|
private static final Transformation IDENTITY;
|
|
|
|
|
|
|
|
public Transformation(@Nullable final Matrix4f b) {
|
|
|
|
if (b == null) {
|
|
|
|
this.matrix = Transformation.IDENTITY.matrix;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.matrix = b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-22 06:32:50 +01:00
|
|
|
public Transformation(@Nullable final Vector3f g1, @Nullable final Quaternion d2, @Nullable final Vector3f g3, @Nullable final Quaternion d4) {
|
|
|
|
this.matrix = compose(g1, d2, g3, d4);
|
|
|
|
this.translation = ((g1 != null) ? g1 : new Vector3f());
|
|
|
|
this.leftRotation = ((d2 != null) ? d2 : Quaternion.ONE.copy());
|
|
|
|
this.scale = ((g3 != null) ? g3 : new Vector3f(1.0f, 1.0f, 1.0f));
|
|
|
|
this.rightRotation = ((d4 != null) ? d4 : Quaternion.ONE.copy());
|
2020-07-22 06:25:47 +01:00
|
|
|
this.decomposed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Transformation identity() {
|
|
|
|
return Transformation.IDENTITY;
|
|
|
|
}
|
|
|
|
|
2020-07-22 06:32:50 +01:00
|
|
|
public Transformation compose(final Transformation f) {
|
2020-07-22 06:25:47 +01:00
|
|
|
final Matrix4f b3 = this.getMatrix();
|
2020-07-22 06:32:50 +01:00
|
|
|
b3.multiply(f.getMatrix());
|
2020-07-22 06:25:47 +01:00
|
|
|
return new Transformation(b3);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nullable
|
|
|
|
public Transformation inverse() {
|
|
|
|
if (this == Transformation.IDENTITY) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
final Matrix4f b2 = this.getMatrix();
|
|
|
|
if (b2.invert()) {
|
|
|
|
return new Transformation(b2);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void ensureDecomposed() {
|
|
|
|
if (!this.decomposed) {
|
|
|
|
final Pair<Matrix3f, Vector3f> pair2 = toAffine(this.matrix);
|
|
|
|
final Triple<Quaternion, Vector3f, Quaternion> triple3 = ((Matrix3f)pair2.getFirst()).svdDecompose();
|
|
|
|
this.translation = (Vector3f)pair2.getSecond();
|
|
|
|
this.leftRotation = (Quaternion)triple3.getLeft();
|
|
|
|
this.scale = (Vector3f)triple3.getMiddle();
|
|
|
|
this.rightRotation = (Quaternion)triple3.getRight();
|
|
|
|
this.decomposed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-22 06:32:50 +01:00
|
|
|
private static Matrix4f compose(@Nullable final Vector3f g1, @Nullable final Quaternion d2, @Nullable final Vector3f g3, @Nullable final Quaternion d4) {
|
2020-07-22 06:25:47 +01:00
|
|
|
final Matrix4f b5 = new Matrix4f();
|
|
|
|
b5.setIdentity();
|
2020-07-22 06:32:50 +01:00
|
|
|
if (d2 != null) {
|
|
|
|
b5.multiply(new Matrix4f(d2));
|
2020-07-22 06:25:47 +01:00
|
|
|
}
|
2020-07-22 06:32:50 +01:00
|
|
|
if (g3 != null) {
|
|
|
|
b5.multiply(Matrix4f.createScaleMatrix(g3.x(), g3.y(), g3.z()));
|
2020-07-22 06:25:47 +01:00
|
|
|
}
|
2020-07-22 06:32:50 +01:00
|
|
|
if (d4 != null) {
|
|
|
|
b5.multiply(new Matrix4f(d4));
|
2020-07-22 06:25:47 +01:00
|
|
|
}
|
2020-07-22 06:32:50 +01:00
|
|
|
if (g1 != null) {
|
|
|
|
b5.m03 = g1.x();
|
|
|
|
b5.m13 = g1.y();
|
|
|
|
b5.m23 = g1.z();
|
2020-07-22 06:25:47 +01:00
|
|
|
}
|
|
|
|
return b5;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Pair<Matrix3f, Vector3f> toAffine(final Matrix4f b) {
|
|
|
|
b.multiply(1.0f / b.m33);
|
2020-07-22 06:32:50 +01:00
|
|
|
final Vector3f g2 = new Vector3f(b.m03, b.m13, b.m23);
|
2020-07-22 06:25:47 +01:00
|
|
|
final Matrix3f a3 = new Matrix3f(b);
|
2020-07-22 06:32:50 +01:00
|
|
|
return (Pair<Matrix3f, Vector3f>)Pair.of(a3, g2);
|
2020-07-22 06:25:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public Matrix4f getMatrix() {
|
|
|
|
return this.matrix.copy();
|
|
|
|
}
|
|
|
|
|
|
|
|
public Quaternion getLeftRotation() {
|
|
|
|
this.ensureDecomposed();
|
|
|
|
return this.leftRotation.copy();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(final Object object) {
|
|
|
|
if (this == object) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (object == null || this.getClass() != object.getClass()) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-07-22 06:32:50 +01:00
|
|
|
final Transformation f3 = (Transformation)object;
|
|
|
|
return Objects.equals(this.matrix, f3.matrix);
|
2020-07-22 06:25:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
|
|
|
return Objects.hash(this.matrix);
|
|
|
|
}
|
|
|
|
|
|
|
|
static {
|
|
|
|
final Matrix4f b1;
|
2020-07-22 06:32:50 +01:00
|
|
|
final Transformation f2;
|
2020-07-22 06:25:47 +01:00
|
|
|
IDENTITY = Util.<Transformation>make(() -> {
|
|
|
|
b1 = new Matrix4f();
|
|
|
|
b1.setIdentity();
|
2020-07-22 06:32:50 +01:00
|
|
|
f2 = new Transformation(b1);
|
|
|
|
f2.getLeftRotation();
|
|
|
|
return f2;
|
2020-07-22 06:25:47 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|