// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.math.matrix;

import com.hypixel.hytale.math.util.TrigMathUtil;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.math.vector.Vector4d;
import com.hypixel.hytale.math.vector.Vector3d;
import java.util.Arrays;
import javax.annotation.Nonnull;

public class Matrix4d
{
    public static final int M00 = 0;
    public static final int M10 = 4;
    public static final int M20 = 8;
    public static final int M30 = 12;
    public static final int M01 = 1;
    public static final int M11 = 5;
    public static final int M21 = 9;
    public static final int M31 = 13;
    public static final int M02 = 2;
    public static final int M12 = 6;
    public static final int M22 = 10;
    public static final int M32 = 14;
    public static final int M03 = 3;
    public static final int M13 = 7;
    public static final int M23 = 11;
    public static final int M33 = 15;
    public static final int COLUMNS = 4;
    public static final int ROWS = 4;
    public static final int FIELDS = 16;
    private final double[] m;
    
    public Matrix4d() {
        this(new double[16]);
    }
    
    public Matrix4d(@Nonnull final Matrix4d other) {
        this();
        this.assign(other);
    }
    
    public Matrix4d(final double[] m) {
        this.m = m;
    }
    
    public double get(final int idx) {
        return this.m[idx];
    }
    
    public double get(final int col, final int row) {
        return this.get(idx(col, row));
    }
    
    @Nonnull
    public Matrix4d set(final int idx, final double val) {
        this.m[idx] = val;
        return this;
    }
    
    @Nonnull
    public Matrix4d set(final int col, final int row, final double val) {
        return this.set(idx(col, row), val);
    }
    
    @Nonnull
    public Matrix4d add(final int idx, final double val) {
        final double[] m = this.m;
        m[idx] += val;
        return this;
    }
    
    @Nonnull
    public Matrix4d add(final int col, final int row, final double val) {
        return this.set(idx(col, row), val);
    }
    
    @Nonnull
    public Matrix4d identity() {
        Arrays.fill(this.m, 0.0);
        for (int i = 0; i < 16; i += 5) {
            this.m[i] = 1.0;
        }
        return this;
    }
    
    @Nonnull
    public Matrix4d assign(@Nonnull final Matrix4d other) {
        System.arraycopy(other.m, 0, this.m, 0, 16);
        return this;
    }
    
    @Nonnull
    public Matrix4d assign(final double m00, final double m10, final double m20, final double m30, final double m01, final double m11, final double m21, final double m31, final double m02, final double m12, final double m22, final double m32, final double m03, final double m13, final double m23, final double m33) {
        this.m[0] = m00;
        this.m[1] = m01;
        this.m[2] = m02;
        this.m[3] = m03;
        this.m[4] = m10;
        this.m[5] = m11;
        this.m[6] = m12;
        this.m[7] = m13;
        this.m[8] = m20;
        this.m[9] = m21;
        this.m[10] = m22;
        this.m[11] = m23;
        this.m[12] = m30;
        this.m[13] = m31;
        this.m[14] = m32;
        this.m[15] = m33;
        return this;
    }
    
    @Nonnull
    public Matrix4d translate(@Nonnull final Vector3d vec) {
        return this.translate(vec.x, vec.y, vec.z);
    }
    
    @Nonnull
    public Matrix4d translate(final double x, final double y, final double z) {
        for (int i = 0; i < 4; ++i) {
            final double[] m = this.m;
            final int n = i + 12;
            m[n] += this.m[i] * x + this.m[i + 4] * y + this.m[i + 8] * z;
        }
        return this;
    }
    
    @Nonnull
    public Matrix4d scale(final double x, final double y, final double z) {
        for (int i = 0; i < 4; ++i) {
            final double[] m = this.m;
            final int n = i;
            m[n] *= x;
            final double[] j = this.m;
            final int n2 = i + 4;
            j[n2] *= y;
            final double[] k = this.m;
            final int n3 = i + 8;
            k[n3] *= z;
        }
        return this;
    }
    
    @Nonnull
    public Vector3d multiplyPosition(@Nonnull final Vector3d vec) {
        return this.multiplyPosition(vec, vec);
    }
    
    @Nonnull
    public Vector3d multiplyPosition(@Nonnull final Vector3d vec, @Nonnull final Vector3d result) {
        final double x = this.m[0] * vec.x + this.m[4] * vec.y + this.m[8] * vec.z + this.m[12];
        final double y = this.m[1] * vec.x + this.m[5] * vec.y + this.m[9] * vec.z + this.m[13];
        final double z = this.m[2] * vec.x + this.m[6] * vec.y + this.m[10] * vec.z + this.m[14];
        final double w = this.m[3] * vec.x + this.m[7] * vec.y + this.m[11] * vec.z + this.m[15];
        final double invW = 1.0 / w;
        result.assign(x * invW, y * invW, z * invW);
        return result;
    }
    
    @Nonnull
    public Vector3d multiplyDirection(@Nonnull final Vector3d vec) {
        final double x = this.m[0] * vec.x + this.m[4] * vec.y + this.m[8] * vec.z;
        final double y = this.m[1] * vec.x + this.m[5] * vec.y + this.m[9] * vec.z;
        final double z = this.m[2] * vec.x + this.m[6] * vec.y + this.m[10] * vec.z;
        vec.assign(x, y, z);
        return vec;
    }
    
    @Nonnull
    public Vector4d multiply(@Nonnull final Vector4d vec) {
        return this.multiply(vec, vec);
    }
    
    @Nonnull
    public Vector4d multiply(@Nonnull final Vector4d vec, @Nonnull final Vector4d result) {
        final double x = this.m[0] * vec.x + this.m[4] * vec.y + this.m[8] * vec.z + this.m[12] * vec.w;
        final double y = this.m[1] * vec.x + this.m[5] * vec.y + this.m[9] * vec.z + this.m[13] * vec.w;
        final double z = this.m[2] * vec.x + this.m[6] * vec.y + this.m[10] * vec.z + this.m[14] * vec.w;
        final double w = this.m[3] * vec.x + this.m[7] * vec.y + this.m[11] * vec.z + this.m[15] * vec.w;
        result.assign(x, y, z, w);
        return result;
    }
    
    @Nonnull
    public Matrix4d multiply(@Nonnull final Matrix4d other) {
        final double a00 = this.m[0];
        final double a2 = this.m[1];
        final double a3 = this.m[2];
        final double a4 = this.m[3];
        final double a5 = this.m[4];
        final double a6 = this.m[5];
        final double a7 = this.m[6];
        final double a8 = this.m[7];
        final double a9 = this.m[8];
        final double a10 = this.m[9];
        final double a11 = this.m[10];
        final double a12 = this.m[11];
        final double a13 = this.m[12];
        final double a14 = this.m[13];
        final double a15 = this.m[14];
        final double a16 = this.m[15];
        final double b00 = other.m[0];
        final double b2 = other.m[1];
        final double b3 = other.m[2];
        final double b4 = other.m[3];
        final double b5 = other.m[4];
        final double b6 = other.m[5];
        final double b7 = other.m[6];
        final double b8 = other.m[7];
        final double b9 = other.m[8];
        final double b10 = other.m[9];
        final double b11 = other.m[10];
        final double b12 = other.m[11];
        final double b13 = other.m[12];
        final double b14 = other.m[13];
        final double b15 = other.m[14];
        final double b16 = other.m[15];
        this.m[0] = a00 * b00 + a5 * b2 + a9 * b3 + a13 * b4;
        this.m[1] = a2 * b00 + a6 * b2 + a10 * b3 + a14 * b4;
        this.m[2] = a3 * b00 + a7 * b2 + a11 * b3 + a15 * b4;
        this.m[3] = a4 * b00 + a8 * b2 + a12 * b3 + a16 * b4;
        this.m[4] = a00 * b5 + a5 * b6 + a9 * b7 + a13 * b8;
        this.m[5] = a2 * b5 + a6 * b6 + a10 * b7 + a14 * b8;
        this.m[6] = a3 * b5 + a7 * b6 + a11 * b7 + a15 * b8;
        this.m[7] = a4 * b5 + a8 * b6 + a12 * b7 + a16 * b8;
        this.m[8] = a00 * b9 + a5 * b10 + a9 * b11 + a13 * b12;
        this.m[9] = a2 * b9 + a6 * b10 + a10 * b11 + a14 * b12;
        this.m[10] = a3 * b9 + a7 * b10 + a11 * b11 + a15 * b12;
        this.m[11] = a4 * b9 + a8 * b10 + a12 * b11 + a16 * b12;
        this.m[12] = a00 * b13 + a5 * b14 + a9 * b15 + a13 * b16;
        this.m[13] = a2 * b13 + a6 * b14 + a10 * b15 + a14 * b16;
        this.m[14] = a3 * b13 + a7 * b14 + a11 * b15 + a15 * b16;
        this.m[15] = a4 * b13 + a8 * b14 + a12 * b15 + a16 * b16;
        return this;
    }
    
    public boolean invert() {
        final double src0 = this.m[0];
        final double src2 = this.m[1];
        final double src3 = this.m[2];
        final double src4 = this.m[3];
        final double src5 = this.m[4];
        final double src6 = this.m[5];
        final double src7 = this.m[6];
        final double src8 = this.m[7];
        final double src9 = this.m[8];
        final double src10 = this.m[9];
        final double src11 = this.m[10];
        final double src12 = this.m[11];
        final double src13 = this.m[12];
        final double src14 = this.m[13];
        final double src15 = this.m[14];
        final double src16 = this.m[15];
        final double atmp0 = src11 * src16;
        final double atmp2 = src15 * src12;
        final double atmp3 = src7 * src16;
        final double atmp4 = src15 * src8;
        final double atmp5 = src7 * src12;
        final double atmp6 = src11 * src8;
        final double atmp7 = src3 * src16;
        final double atmp8 = src15 * src4;
        final double atmp9 = src3 * src12;
        final double atmp10 = src11 * src4;
        final double atmp11 = src3 * src8;
        final double atmp12 = src7 * src4;
        final double dst0 = atmp0 * src6 + atmp4 * src10 + atmp5 * src14 - (atmp2 * src6 + atmp3 * src10 + atmp6 * src14);
        final double dst2 = atmp2 * src2 + atmp7 * src10 + atmp10 * src14 - (atmp0 * src2 + atmp8 * src10 + atmp9 * src14);
        final double dst3 = atmp3 * src2 + atmp8 * src6 + atmp11 * src14 - (atmp4 * src2 + atmp7 * src6 + atmp12 * src14);
        final double dst4 = atmp6 * src2 + atmp9 * src6 + atmp12 * src10 - (atmp5 * src2 + atmp10 * src6 + atmp11 * src10);
        final double dst5 = atmp2 * src5 + atmp3 * src9 + atmp6 * src13 - (atmp0 * src5 + atmp4 * src9 + atmp5 * src13);
        final double dst6 = atmp0 * src0 + atmp8 * src9 + atmp9 * src13 - (atmp2 * src0 + atmp7 * src9 + atmp10 * src13);
        final double dst7 = atmp4 * src0 + atmp7 * src5 + atmp12 * src13 - (atmp3 * src0 + atmp8 * src5 + atmp11 * src13);
        final double dst8 = atmp5 * src0 + atmp10 * src5 + atmp11 * src9 - (atmp6 * src0 + atmp9 * src5 + atmp12 * src9);
        final double btmp0 = src9 * src14;
        final double btmp2 = src13 * src10;
        final double btmp3 = src5 * src14;
        final double btmp4 = src13 * src6;
        final double btmp5 = src5 * src10;
        final double btmp6 = src9 * src6;
        final double btmp7 = src0 * src14;
        final double btmp8 = src13 * src2;
        final double btmp9 = src0 * src10;
        final double btmp10 = src9 * src2;
        final double btmp11 = src0 * src6;
        final double btmp12 = src5 * src2;
        final double dst9 = btmp0 * src8 + btmp4 * src12 + btmp5 * src16 - (btmp2 * src8 + btmp3 * src12 + btmp6 * src16);
        final double dst10 = btmp2 * src4 + btmp7 * src12 + btmp10 * src16 - (btmp0 * src4 + btmp8 * src12 + btmp9 * src16);
        final double dst11 = btmp3 * src4 + btmp8 * src8 + btmp11 * src16 - (btmp4 * src4 + btmp7 * src8 + btmp12 * src16);
        final double dst12 = btmp6 * src4 + btmp9 * src8 + btmp12 * src12 - (btmp5 * src4 + btmp10 * src8 + btmp11 * src12);
        final double dst13 = btmp3 * src11 + btmp6 * src15 + btmp2 * src7 - (btmp5 * src15 + btmp0 * src7 + btmp4 * src11);
        final double dst14 = btmp9 * src15 + btmp0 * src3 + btmp8 * src11 - (btmp7 * src11 + btmp10 * src15 + btmp2 * src3);
        final double dst15 = btmp7 * src7 + btmp12 * src15 + btmp4 * src3 - (btmp11 * src15 + btmp3 * src3 + btmp8 * src7);
        final double dst16 = btmp11 * src11 + btmp5 * src3 + btmp10 * src7 - (btmp9 * src7 + btmp12 * src11 + btmp6 * src3);
        final double det = src0 * dst0 + src5 * dst2 + src9 * dst3 + src13 * dst4;
        if (det == 0.0) {
            return false;
        }
        final double invdet = 1.0 / det;
        this.m[0] = dst0 * invdet;
        this.m[1] = dst2 * invdet;
        this.m[2] = dst3 * invdet;
        this.m[3] = dst4 * invdet;
        this.m[4] = dst5 * invdet;
        this.m[5] = dst6 * invdet;
        this.m[6] = dst7 * invdet;
        this.m[7] = dst8 * invdet;
        this.m[8] = dst9 * invdet;
        this.m[9] = dst10 * invdet;
        this.m[10] = dst11 * invdet;
        this.m[11] = dst12 * invdet;
        this.m[12] = dst13 * invdet;
        this.m[13] = dst14 * invdet;
        this.m[14] = dst15 * invdet;
        this.m[15] = dst16 * invdet;
        return true;
    }
    
    @Nonnull
    public Matrix4d projectionOrtho(final double left, final double right, final double bottom, final double top, final double near, final double far) {
        final double r_width = 1.0 / (right + left);
        final double r_height = 1.0 / (top + bottom);
        final double r_depth = -1.0 / (far - near);
        final double x = 2.0 * r_width;
        final double y = 2.0 * r_height;
        final double z = 2.0 * r_depth;
        final double[] m = this.m;
        final int n = 1;
        final double[] i = this.m;
        final int n2 = 2;
        final double[] j = this.m;
        final int n3 = 3;
        final double n4 = 0.0;
        j[n3] = n4;
        m[n] = (i[n2] = n4);
        final double[] k = this.m;
        final int n5 = 4;
        final double[] l = this.m;
        final int n6 = 6;
        final double[] m2 = this.m;
        final int n7 = 7;
        final double n8 = 0.0;
        m2[n7] = n8;
        k[n5] = (l[n6] = n8);
        final double[] m3 = this.m;
        final int n9 = 8;
        final double[] m4 = this.m;
        final int n10 = 9;
        final double[] m5 = this.m;
        final int n11 = 11;
        final double n12 = 0.0;
        m5[n11] = n12;
        m3[n9] = (m4[n10] = n12);
        this.m[15] = 1.0;
        this.m[0] = x;
        this.m[5] = y;
        this.m[10] = z;
        this.m[12] = -(right - left) * r_width;
        this.m[13] = -(top - bottom) * r_height;
        this.m[14] = (far + near) * r_depth;
        return this;
    }
    
    @Nonnull
    public Matrix4d projectionFrustum(final double left, final double right, final double bottom, final double top, final double near, final double far) {
        final double r_width = 1.0 / (right + left);
        final double r_height = 1.0 / (top + bottom);
        final double r_depth = 1.0 / (near - far);
        final double[] m = this.m;
        final int n = 1;
        final double[] i = this.m;
        final int n2 = 2;
        final double[] j = this.m;
        final int n3 = 3;
        final double n4 = 0.0;
        j[n3] = n4;
        m[n] = (i[n2] = n4);
        final double[] k = this.m;
        final int n5 = 4;
        final double[] l = this.m;
        final int n6 = 6;
        final double[] m2 = this.m;
        final int n7 = 7;
        final double n8 = 0.0;
        m2[n7] = n8;
        k[n5] = (l[n6] = n8);
        final double[] m3 = this.m;
        final int n9 = 12;
        final double[] m4 = this.m;
        final int n10 = 13;
        final double[] m5 = this.m;
        final int n11 = 15;
        final double n12 = 0.0;
        m5[n11] = n12;
        m3[n9] = (m4[n10] = n12);
        this.m[11] = -1.0;
        this.m[0] = 2.0 * (near * r_width);
        this.m[5] = 2.0 * (near * r_height);
        this.m[14] = 2.0 * (far * near * r_depth);
        this.m[8] = 2.0 * (right - left) * r_width;
        this.m[9] = (top - bottom) * r_height;
        this.m[10] = (far + near) * r_depth;
        return this;
    }
    
    @Nonnull
    public Matrix4d projectionCone(final double fov, final double aspect, final double near, final double far) {
        final double f = 1.0 / Math.tan(fov * 0.5);
        final double r = 1.0 / (near - far);
        this.m[0] = f / aspect;
        final double[] m = this.m;
        final int n = 1;
        final double[] i = this.m;
        final int n2 = 2;
        final double[] j = this.m;
        final int n3 = 3;
        final double n4 = 0.0;
        j[n3] = n4;
        m[n] = (i[n2] = n4);
        this.m[5] = f;
        final double[] k = this.m;
        final int n5 = 4;
        final double[] l = this.m;
        final int n6 = 6;
        final double[] m2 = this.m;
        final int n7 = 7;
        final double n8 = 0.0;
        m2[n7] = n8;
        k[n5] = (l[n6] = n8);
        this.m[8] = (this.m[9] = 0.0);
        this.m[10] = (far + near) * r;
        this.m[11] = -1.0;
        final double[] m3 = this.m;
        final int n9 = 12;
        final double[] m4 = this.m;
        final int n10 = 13;
        final double[] m5 = this.m;
        final int n11 = 15;
        final double n12 = 0.0;
        m5[n11] = n12;
        m3[n9] = (m4[n10] = n12);
        this.m[14] = 2.0 * far * near * r;
        return this;
    }
    
    @Nonnull
    public Matrix4d viewTarget(final double eyeX, final double eyeY, final double eyeZ, final double centerX, final double centerY, final double centerZ, final double upX, final double upY, final double upZ) {
        final double dirX = centerX - eyeX;
        final double dirY = centerY - eyeY;
        final double dirZ = centerZ - eyeZ;
        return this.viewDirection(eyeX, eyeY, eyeZ, dirX, dirY, dirZ, upX, upY, upZ);
    }
    
    @Nonnull
    public Matrix4d viewDirection(final double eyeX, final double eyeY, final double eyeZ, double dirX, double dirY, double dirZ, final double upX, final double upY, final double upZ) {
        final double rlf = 1.0 / MathUtil.length(dirX, dirY, dirZ);
        dirX *= rlf;
        dirY *= rlf;
        dirZ *= rlf;
        double sx = dirY * upZ - dirZ * upY;
        double sy = dirZ * upX - dirX * upZ;
        double sz = dirX * upY - dirY * upX;
        final double rls = 1.0 / MathUtil.length(sx, sy, sz);
        sx *= rls;
        sy *= rls;
        sz *= rls;
        final double ux = sy * dirZ - sz * dirY;
        final double uy = sz * dirX - sx * dirZ;
        final double uz = sx * dirY - sy * dirX;
        this.m[0] = sx;
        this.m[1] = ux;
        this.m[2] = -dirX;
        this.m[3] = 0.0;
        this.m[4] = sy;
        this.m[5] = uy;
        this.m[6] = -dirY;
        this.m[7] = 0.0;
        this.m[8] = sz;
        this.m[9] = uz;
        this.m[10] = -dirZ;
        this.m[11] = 0.0;
        this.m[12] = 0.0;
        this.m[13] = 0.0;
        this.m[14] = 0.0;
        this.m[15] = 1.0;
        this.translate(-eyeX, -eyeY, -eyeZ);
        return this;
    }
    
    @Nonnull
    public Matrix4d rotateAxis(final double a, final double x, final double y, final double z, @Nonnull final Matrix4d tmp) {
        return this.multiply(tmp.setRotateAxis(a, x, y, z));
    }
    
    @Nonnull
    public Matrix4d setRotateAxis(final double a, final double x, final double y, final double z) {
        final double sin = TrigMathUtil.sin(a);
        final double cos = TrigMathUtil.cos(a);
        this.m[0] = cos + x * x * (1.0 - cos);
        this.m[1] = x * y * (1.0 - cos) - z * sin;
        this.m[2] = x * z * (1.0 - cos) + y * sin;
        this.m[3] = 0.0;
        this.m[4] = y * x * (1.0 - cos) + z * sin;
        this.m[5] = cos + y * y * (1.0 - cos);
        this.m[6] = y * z * (1.0 - cos) - x * sin;
        this.m[7] = 0.0;
        this.m[8] = z * x * (1.0 - cos) - y * sin;
        this.m[9] = z * y * (1.0 - cos) + x * sin;
        this.m[10] = cos + z * z * (1.0 - cos);
        this.m[11] = 0.0;
        this.m[12] = 0.0;
        this.m[13] = 0.0;
        this.m[14] = 0.0;
        this.m[15] = 1.0;
        return this;
    }
    
    @Nonnull
    public Matrix4d rotateEuler(final double x, final double y, final double z, @Nonnull final Matrix4d tmp) {
        return this.multiply(tmp.setRotateEuler(x, y, z));
    }
    
    @Nonnull
    public Matrix4d setRotateEuler(final double x, final double y, final double z) {
        final double cx = TrigMathUtil.cos(x);
        final double sx = TrigMathUtil.sin(x);
        final double cy = TrigMathUtil.cos(y);
        final double sy = TrigMathUtil.sin(y);
        final double cz = TrigMathUtil.cos(z);
        final double sz = TrigMathUtil.sin(z);
        final double cxsy = cx * sy;
        final double sxsy = sx * sy;
        this.m[0] = cy * cz;
        this.m[1] = -cy * sz;
        this.m[2] = sy;
        this.m[4] = sxsy * cz + cx * sz;
        this.m[5] = -sxsy * sz + cx * cz;
        this.m[6] = -sx * cy;
        this.m[8] = -cxsy * cz + sx * sz;
        this.m[9] = cxsy * sz + sx * cz;
        this.m[10] = cx * cy;
        final double[] m = this.m;
        final int n = 3;
        final double[] i = this.m;
        final int n2 = 7;
        final double[] j = this.m;
        final int n3 = 11;
        final double n4 = 0.0;
        j[n3] = n4;
        m[n] = (i[n2] = n4);
        final double[] k = this.m;
        final int n5 = 12;
        final double[] l = this.m;
        final int n6 = 13;
        final double[] m2 = this.m;
        final int n7 = 14;
        final double n8 = 0.0;
        m2[n7] = n8;
        k[n5] = (l[n6] = n8);
        this.m[15] = 1.0;
        return this;
    }
    
    public double[] getData() {
        return this.m;
    }
    
    public float[] asFloatData() {
        final float[] data = new float[16];
        for (int i = 0; i < 16; ++i) {
            data[i] = (float)this.m[i];
        }
        return data;
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "Matrix4d{\n  " + this.m[0] + " " + this.m[4] + " " + this.m[8] + " " + this.m[12] + "\n  " + this.m[1] + " " + this.m[5] + " " + this.m[9] + " " + this.m[13] + "\n  " + this.m[2] + " " + this.m[6] + " " + this.m[10] + " " + this.m[14] + "\n  " + this.m[3] + " " + this.m[7] + " " + this.m[11] + " " + this.m[15] + "\n}";
    }
    
    public static int idx(final int col, final int row) {
        return col << 2 | row;
    }
}
