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; } } public Transformation(@Nullable final Vector3f e1, @Nullable final Quaternion c2, @Nullable final Vector3f e3, @Nullable final Quaternion c4) { this.matrix = compose(e1, c2, e3, c4); this.translation = ((e1 != null) ? e1 : new Vector3f()); this.leftRotation = ((c2 != null) ? c2 : Quaternion.ONE.copy()); this.scale = ((e3 != null) ? e3 : new Vector3f(1.0f, 1.0f, 1.0f)); this.rightRotation = ((c4 != null) ? c4 : Quaternion.ONE.copy()); this.decomposed = true; } public static Transformation identity() { return Transformation.IDENTITY; } public Transformation compose(final Transformation d) { final Matrix4f b3 = this.getMatrix(); b3.multiply(d.getMatrix()); 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 pair2 = toAffine(this.matrix); final Triple 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; } } private static Matrix4f compose(@Nullable final Vector3f e1, @Nullable final Quaternion c2, @Nullable final Vector3f e3, @Nullable final Quaternion c4) { final Matrix4f b5 = new Matrix4f(); b5.setIdentity(); if (c2 != null) { b5.multiply(new Matrix4f(c2)); } if (e3 != null) { b5.multiply(Matrix4f.createScaleMatrix(e3.x(), e3.y(), e3.z())); } if (c4 != null) { b5.multiply(new Matrix4f(c4)); } if (e1 != null) { b5.m03 = e1.x(); b5.m13 = e1.y(); b5.m23 = e1.z(); } return b5; } public static Pair toAffine(final Matrix4f b) { b.multiply(1.0f / b.m33); final Vector3f e2 = new Vector3f(b.m03, b.m13, b.m23); final Matrix3f a3 = new Matrix3f(b); return (Pair)Pair.of(a3, e2); } 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; } final Transformation d3 = (Transformation)object; return Objects.equals(this.matrix, d3.matrix); } @Override public int hashCode() { return Objects.hash(this.matrix); } static { final Matrix4f b1; final Transformation d2; IDENTITY = Util.make(() -> { b1 = new Matrix4f(); b1.setIdentity(); d2 = new Transformation(b1); d2.getLeftRotation(); return d2; }); } }