New matrix4f

Changes:


  1. New Matrix4f does proper matrix multiplication
  2. Javadoc updated, (for instance it would say a throw for MonkeyRuntimeException but would really throw JmeException)
  3. private float[][] matrix became public float m01,m02,m03,ect





    Testing:



    A test script is included to insure changes are compatable



    Post Note: Spacing isn’t working when pasting code, can I email it?

import com.jme.math.Quaternion;

import com.jme.math.Vector3f;

import com.jme.util.LoggingSystem;

import com.jme.system.JmeException;



import java.util.logging.Level;





/**

  • <code>Matrix4f</code> defines and maintains a 4x4 matrix. This matrix is
  • intended for use in a translation and rotational capacity. It provides
  • convinience methods for creating the matrix from a multitude of sources.

    *
  • @author Mark Powell, updates by Jack Lindamood

    */

    public class Matrixx4f {



    // m23 refers to row 3 from top and column 4 from left(remember 0 indexed)

    public float m00, m01, m02, m03;

    public float m10, m11, m12, m13;

    public float m20, m21, m22, m23;

    public float m30, m31, m32, m33;





    /**
  • Constructor instantiates a new <code>Matrix</code> that is set to the
  • identity matrix.

    *

    */

    public Matrixx4f() {

    loadIdentity();

    }



    /**
  • Constructor instantiates a new <code>Matrix</code> that is set to the
  • provided matrix. This constructor copies a given Matrix. If the
  • provided matrix is null, the constructor sets the matrix to the
  • identity.
  • @param mat the matrix to copy.

    */

    public Matrixx4f(Matrixx4f mat) {

    copy(mat);

    }



    /**
  • <code>copy</code> transfers the contents of a given matrix to this
  • matrix. If a null matrix is supplied, this matrix is set to the
  • identity matrix.
  • @param matrix the matrix to copy.

    */

    public void copy(Matrixx4f matrix) {

    if (null == matrix) {

    loadIdentity();

    } else {

    this.m00=matrix.m00;

    this.m01=matrix.m01;

    this.m02=matrix.m02;

    this.m03=matrix.m03;

    this.m10=matrix.m10;

    this.m11=matrix.m11;

    this.m12=matrix.m12;

    this.m13=matrix.m13;

    this.m20=matrix.m20;

    this.m21=matrix.m21;

    this.m22=matrix.m22;

    this.m23=matrix.m23;

    this.m30=matrix.m30;

    this.m31=matrix.m31;

    this.m32=matrix.m32;

    this.m33=matrix.m33;

    }

    }



    /**
  • <code>get</code> retrieves a value from the matrix at the given
  • position.
  • @param i the row index.
  • @param j the colum index.
  • @return the value at (i, j).
  • @throws JmeException if i,j is an invalid position

    */

    public float get(int i, int j) {

    switch (i){

    case 0:

    switch (j){

    case 0: return m00;

    case 1: return m01;

    case 2: return m02;

    case 3: return m03;

    }

    break;

    case 1:

    switch(j){

    case 0: return m10;

    case 1: return m11;

    case 2: return m12;

    case 3: return m13;



    }

    break;

    case 2:

    switch(j){

    case 0: return m20;

    case 1: return m21;

    case 2: return m22;

    case 3: return m23;

    }

    break;

    case 3:

    switch(j){

    case 0: return m30;

    case 1: return m31;

    case 2: return m32;

    case 3: return m33;

    }

    break;

    }

    LoggingSystem.getLogger().log(

    Level.WARNING,

    "Invalid matrix index.");

    throw new JmeException("Invalid indices into matrix ("+i+"),("+j+")");

    }



    /**
  • <code>getColumn</code> returns one of three columns specified by the
  • parameter. This column is returned as a float array of length 4.

    *
  • @param i the column to retrieve. Must be between 0 and 3.
  • @return the column specified by the index.
  • @throws JmeException if the colum index is invalid

    */

    public float[] getColumn(int i) {

    switch(i){

    case 0:

    return new float[]{m00,m10,m20,m30};

    case 1:

    return new float[]{m01,m11,m21,m31};

    case 2:

    return new float[]{m02,m12,m22,m32};

    case 3:

    return new float[]{m03,m13,m23,m33};

    }

    LoggingSystem.getLogger().log(

    Level.WARNING,

    "Invalid column index.");

    throw new JmeException("Invalid column index. " + i);

    }



    /**

    *
  • <code>setColumn</code> sets a particular column of this matrix to that
  • represented by the provided vector.
  • @param i the column to set.
  • @param column the data to set.
  • @throws JmeException if the colum index is invalid or if <code>column.length!=4</code>

    */

    public void setColumn(int i, float[] column) {

    if (column.length != 4) {

    LoggingSystem.getLogger().log(

    Level.WARNING,

    "Column is not length 4. Ignoring.");

    return;

    }

    switch (i){

    case 0:

    m00=column[0];

    m10=column[1];

    m20=column[2];

    m30=column[3];

    return;

    case 1:

    m01=column[0];

    m11=column[1];

    m21=column[2];

    m31=column[3];

    return;

    case 2:

    m02=column[0];

    m12=column[1];

    m22=column[2];

    m32=column[3];

    return;

    case 3:

    m03=column[0];

    m13=column[1];

    m23=column[2];

    m33=column[3];

    return;

    }



    LoggingSystem.getLogger().log(

    Level.WARNING,

    "Invalid column index.");

    throw new JmeException("Invalid column index. " + i);

    }



    /**
  • <code>set</code> places a given value into the matrix at the given
  • position.
  • @param i the row index.
  • @param j the colum index.
  • @param value the value for (i, j).
  • @throws JmeException if position is invalid

    */

    public void set(int i, int j, float value) {

    if (i<0 || i>3 || j<0 || j>3){

    LoggingSystem.getLogger().log(

    Level.WARNING,

    "Invalid matrix index.");

    throw new JmeException("Invalid indices into matrix set ("+i+"),("+j+")");

    }

    if (i==0){

    if (j==0) m00=value;

    else if (j==1) m01=value;

    else if (j==2) m02=value;

    else if (j=:3) m03=value;

    }

    else if (i==1){

    if (j==0) m10=value;

    else if (j==1) m11=value;

    else if (j==2) m12=value;

    else if (j=:3) m13=value;

    }

    else if (i==2){

    if (j==0) m20=value;

    else if (j==1) m21=value;

    else if (j==2) m22=value;

    else if (j=:3) m23=value;

    }

    else if (i=:3){

    if (j==0) m30=value;

    else if (j==1) m31=value;

    else if (j==2) m32=value;

    else if (j=:3) m33=value;

    }

    }



    /**
  • <code>set</code> copies the values of this matrix from an array of
  • values.
  • @param matrix the matrix to set the value to.
  • @throws JmeException if the array is not of size 16.

    */

    public void set(float[][] matrix) {

    if (matrix==null || matrix.length != 4 || matrix[0].length != 4) {

    throw new JmeException("Array must be of size 16.");

    }

    this.m00=matrix[0][0];

    this.m01=matrix[0][1];

    this.m02=matrix[0][2];

    this.m03=matrix[0][3];

    this.m10=matrix[1][0];

    this.m11=matrix[1][1];

    this.m12=matrix[1][2];

    this.m13=matrix[1][3];

    this.m20=matrix[2][0];

    this.m21=matrix[2][1];

    this.m22=matrix[2][2];

    this.m23=matrix[2][3];

    this.m30=matrix[3][0];

    this.m31=matrix[3][1];

    this.m32=matrix[3][2];

    this.m33=matrix[3][3];

    }



    /**
  • <code>set</code> sets the values of this matrix from an array of
  • values;
  • @param matrix the matrix to set the value to.
  • @throws JmeException if <code>matrix==null || matrix.lenght!=16</code>

    */

    public void set(float[] matrix) {

    if (matrix==null || matrix.length != 16) {

    throw new JmeException("Array must be of size 16.");

    }

    this.m00=matrix[0];

    this.m01=matrix[1];

    this.m02=matrix[2];

    this.m03=matrix[3];

    this.m10=matrix[4];

    this.m11=matrix[5];

    this.m12=matrix[6];

    this.m13=matrix[7];

    this.m20=matrix[8];

    this.m21=matrix[9];

    this.m22=matrix[10];

    this.m23=matrix[11];

    this.m30=matrix[12];

    this.m31=matrix[13];

    this.m32=matrix[14];

    this.m33=matrix[15];

    }



    /**

    *
  • <code>set</code> defines the values of the matrix based on a supplied
  • <code>Quaternion</code>. It should be noted that all previous values
  • will be overridden.
  • @param quaternion the quaternion to create a rotational matrix from.

    */

    public void set(Quaternion quaternion) {

    loadIdentity();

    m00 =

    (float) (1.0
  • 2.0 * quaternion.y * quaternion.y
  • 2.0 * quaternion.z * quaternion.z);

    m10 =

    (float) (2.0 * quaternion.x * quaternion.y
  • 2.0 * quaternion.w * quaternion.z);

    m20 =

    (float) (2.0 * quaternion.x * quaternion.z
  • 2.0 * quaternion.w * quaternion.y);



    m01 =

    (float) (2.0 * quaternion.x * quaternion.y
  • 2.0 * quaternion.w * quaternion.z);

    m11 =

    (float) (1.0
  • 2.0 * quaternion.x * quaternion.x
  • 2.0 * quaternion.z * quaternion.z);

    m21 =

    (float) (2.0 * quaternion.y * quaternion.z
  • 2.0 * quaternion.w * quaternion.x);



    m02 =

    (float) (2.0 * quaternion.x * quaternion.z
  • 2.0 * quaternion.w * quaternion.y);

    m12 =

    (float) (2.0 * quaternion.y * quaternion.z
  • 2.0 * quaternion.w * quaternion.x);

    m22 =

    (float) (1.0
  • 2.0 * quaternion.x * quaternion.x
  • 2.0 * quaternion.y * quaternion.y);



    }



    /**
  • <code>loadIdentity</code> sets this matrix to the identity matrix,
  • namely all zeros with ones along the diagonal.

    *

    */

    public void loadIdentity() {

    m00=m11=m22=m33=1;

    m01=m02=m03=0;

    m10=m12=m13=0;

    m20=m21=m23=0;

    m30=m31=m32=0;

    }



    /**
  • Multiplies every value in the matrix by a scalar
  • @param scalar

    /

    public void mult(float scalar) {

    m00
    =scalar;

    m01*=scalar;

    m02*=scalar;

    m03*=scalar;

    m10*=scalar;

    m11*=scalar;

    m12*=scalar;

    m13*=scalar;

    m20*=scalar;

    m21*=scalar;

    m22*=scalar;

    m23*=scalar;

    m30*=scalar;

    m31*=scalar;

    m32*=scalar;

    m33*=scalar;

    }



    /**
  • <code>mult</code> multiplies this matrix with another matrix. The
  • result matrix will then be returned.
  • This matrix will be on the left hand side, while the parameter matrix
  • will be on the right. If in2 == null, null is returned
  • @param in2 the matrix to multiply this matrix by.
  • @return the resultant matrix

    */

    public Matrixx4f mult(Matrixx4f in2) {

    if (in2==null){

    LoggingSystem.getLogger().log(

    Level.WARNING,

    "Source Matrix is null, null result returned.");

    return null;

    }

    Matrixx4f out = new Matrixx4f();

    out.m00 = m00 * in2.m00 + m01 * in2.m10 + m02 * in2.m20 + m03 * in2.m30;

    out.m01 = m00 * in2.m01 + m01 * in2.m11 + m02 * in2.m21 + m03 * in2.m31;

    out.m02 = m00 * in2.m02 + m01 * in2.m12 + m02 * in2.m22 + m03 * in2.m32;

    out.m03 = m00 * in2.m03 + m01 * in2.m13 + m02 * in2.m23 + m03 * in2.m33;

    out.m10 = m10 * in2.m00 + m11 * in2.m10 + m12 * in2.m20 + m13 * in2.m30;

    out.m11 = m10 * in2.m01 + m11 * in2.m11 + m12 * in2.m21 + m13 * in2.m31;

    out.m12 = m10 * in2.m02 + m11 * in2.m12 + m12 * in2.m22 + m13 * in2.m32;

    out.m13 = m10 * in2.m03 + m11 * in2.m13 + m12 * in2.m23 + m13 * in2.m33;

    out.m20 = m20 * in2.m00 + m21 * in2.m10 + m22 * in2.m20 + m23 * in2.m30;

    out.m21 = m20 * in2.m01 + m21 * in2.m11 + m22 * in2.m21 + m23 * in2.m31;

    out.m22 = m20 * in2.m02 + m21 * in2.m12 + m22 * in2.m22 + m23 * in2.m32;

    out.m23 = m20 * in2.m03 + m21 * in2.m13 + m22 * in2.m23 + m23 * in2.m33;

    out.m30 = m30 * in2.m00 + m31 * in2.m10 + m32 * in2.m20 + m33 * in2.m30;

    out.m31 = m30 * in2.m01 + m31 * in2.m11 + m32 * in2.m21 + m33 * in2.m31;

    out.m32 = m30 * in2.m02 + m31 * in2.m12 + m32 * in2.m22 + m33 * in2.m32;

    out.m33 = m30 * in2.m03 + m31 * in2.m13 + m32 * in2.m23 + m33 * in2.m33;

    return out;

    }



    /**
  • <code>mult</code> multiplies a vector about a rotation matrix. The
  • resulting vector is returned.
  • @param vec the rotation matrix.
  • @return the rotated vector.

    */

    public Vector3f mult(Vector3f vec) {

    if (null == vec) {

    LoggingSystem.getLogger().log(

    Level.WARNING,

    "Source vector is null, null result returned.");

    return null;

    }

    Vector3f product = new Vector3f();

    product.x =

    m00 * vec.x + m01 * vec.y + m02 * vec.z;

    product.y =

    m10 * vec.x + m11 * vec.y + m12 * vec.z;

    product.z =

    m20 * vec.x + m21 * vec.y + m22 * vec.z;

    return product;

    }

    /**
  • <code>add</code> adds the values of a parameter matrix to this matrix.
  • @param matrix the matrix to add to this.

    */

    public void add(Matrixx4f matrix) {

    if (matrix==null) return;

    this.m00+=matrix.m00;

    this.m01+=matrix.m01;

    this.m02+=matrix.m02;

    this.m03+=matrix.m03;

    this.m10+=matrix.m10;

    this.m11+=matrix.m11;

    this.m12+=matrix.m12;

    this.m13+=matrix.m13;

    this.m20+=matrix.m20;

    this.m21+=matrix.m21;

    this.m22+=matrix.m22;

    this.m23+=matrix.m23;

    this.m30+=matrix.m30;

    this.m31+=matrix.m31;

    this.m32+=matrix.m32;

    this.m33+=matrix.m33;

    }



    /**
  • <code>setTranslation</code> will set the matrix’s translation values.
  • @param translation the new values for the translation.
  • @throws JmeException if translation is null or not size 3.

    */

    public void setTranslation(float[] translation) {

    if (translation == null || translation.length != 3) {

    throw new JmeException("Translation size must be 3.");

    }

    m30 = translation[0];

    m31 = translation[1];

    m32 = translation[2];

    }



    /**
  • <code>setInverseTranslation</code> will set the matrix’s inverse
  • translation values.
  • @param translation the new values for the inverse translation.
  • @throws JmeException if translation is null or not size 3.

    */

    public void setInverseTranslation(float[] translation) {

    if (translation==null || translation.length != 3) {

    throw new JmeException("Translation size must be 3.");

    }

    m30 = -translation[0];

    m31 = -translation[1];

    m32 = -translation[2];

    }



    /**
  • <code>angleRotation</code> sets this matrix to that
  • of a rotation about three axes (x, y, z). Where each
  • axis has a specified rotation in degrees. These rotations
  • are expressed in a single <code>Vector3f</code> object.
  • @param angles the angles to rotate.

    */

    public void angleRotation(Vector3f angles) {

    double angle;

    double sr, sp, sy, cr, cp, cy;



    angle = angles.z * (Math.PI * 2 / 360);

    sy = Math.sin(angle);

    cy = Math.cos(angle);

    angle = angles.y * (Math.PI * 2 / 360);

    sp = Math.sin(angle);

    cp = Math.cos(angle);

    angle = angles.x * (Math.PI * 2 / 360);

    sr = Math.sin(angle);

    cr = Math.cos(angle);



    // matrix = (Z * Y) * X

    m00 = (float) (cp * cy);

    m10 = (float) (cp * sy);

    m20 = (float) -sp;

    m01 = (float) (sr * sp * cy + cr * -sy);

    m11 = (float) (sr * sp * sy + cr * cy);

    m21 = (float) (sr * cp);

    m02 = (float) (cr * sp * cy + -sr * -sy);

    m12 = (float) (cr * sp * sy + -sr * cy);

    m22 = (float) (cr * cp);

    m03 = 0.0f;

    m13 = 0.0f;

    m23 = 0.0f;

    }



    /**
  • <code>setRotationQuaternion</code> builds a rotation from a
  • <code>Quaternion</code>.
  • @param quat the quaternion to build the rotation from.
  • @throws JmeException if quat is null.

    */

    public void setRotationQuaternion(Quaternion quat) {

    if (null == quat) {

    throw new JmeException("Quat may not be null.");

    }

    m00 = (float) (1.0 - 2.0 * quat.y * quat.y - 2.0 * quat.z * quat.z);

    m01 = (float) (2.0 * quat.x * quat.y + 2.0 * quat.w * quat.z);

    m02 = (float) (2.0 * quat.x * quat.z - 2.0 * quat.w * quat.y);



    m10 = (float) (2.0 * quat.x * quat.y - 2.0 * quat.w * quat.z);

    m11 = (float) (1.0 - 2.0 * quat.x * quat.x - 2.0 * quat.z * quat.z);

    m12 = (float) (2.0 * quat.y * quat.z + 2.0 * quat.w * quat.x);



    m20 = (float) (2.0 * quat.x * quat.z + 2.0 * quat.w * quat.y);

    m21 = (float) (2.0 * quat.y * quat.z - 2.0 * quat.w * quat.x);

    m22 = (float) (1.0 - 2.0 * quat.x * quat.x - 2.0 * quat.y * quat.y);

    }



    /**
  • <code>setInverseRotationRadians</code> builds an inverted rotation
  • from Euler angles that are in radians.
  • @param angles the Euler angles in radians.
  • @throws JmeException if angles is not size 3.

    */

    public void setInverseRotationRadians(float[] angles) {

    if (angles.length != 3) {

    throw new JmeException("Angles must be of size 3.");

    }

    double cr = Math.cos(angles[0]);

    double sr = Math.sin(angles[0]);

    double cp = Math.cos(angles[1]);

    double sp = Math.sin(angles[1]);

    double cy = Math.cos(angles[2]);

    double sy = Math.sin(angles[2]);



    m00 = (float) (cp * cy);

    m10 = (float) (cp * sy);

    m20 = (float) -sp;



    double srsp = sr * sp;

    double crsp = cr * sp;



    m01 = (float) (srsp * cy - cr * sy);

    m11 = (float) (srsp * sy + cr * cy);

    m21 = (float) (sr * cp);



    m02 = (float) (crsp * cy + sr * sy);

    m12 = (float) (crsp * sy - sr * cy);

    m22 = (float) (cr * cp);

    }



    /**
  • <code>setInverseRotationDegrees</code> builds an inverted rotation
  • from Euler angles that are in degrees.
  • @param angles the Euler angles in degrees.
  • @throws JmeException if angles is null or not size 3.

    */

    public void setInverseRotationDegrees(float[] angles) {

    if (angles == null || angles.length != 3) {

    throw new JmeException("Angles must be of size 3.");

    }

    float vec[] = new float[3];

    vec[0] = (float) (angles[0] * 180.0 / Math.PI);

    vec[1] = (float) (angles[1] * 180.0 / Math.PI);

    vec[2] = (float) (angles[2] * 180.0 / Math.PI);

    setInverseRotationRadians(vec);

    }



    /**

    *
  • <code>inverseTranslateVect</code> translates a given Vector3f by the
  • inverse translation part of this matrix.
  • @param vector3f the Vector3f to be translated.
  • @throws JmeException if vec is null or not size 3.

    */

    public void inverseTranslateVect(float[] vector3f) {

    if (vector3f == null || vector3f.length != 3) {

    throw new JmeException("Vector3f must be of size 3.");

    }



    vector3f[0] = vector3f[0] - m30;

    vector3f[1] = vector3f[1] - m31;

    vector3f[2] = vector3f[2] - m32;

    }



    /**

    *
  • <code>inverseRotateVect</code> rotates a given Vector3f by the rotation
  • part of this matrix.
  • @param vec the Vector3f to be rotated.
  • @throws JmeException if vec is null or size is not 3.

    */

    public void inverseRotateVect(float[] vec) {

    if (vec==null || vec.length != 3) {

    throw new JmeException("Vector3f must be of size 3.");

    }



    vec[0] =

    vec[0] * m00
  • vec[1] * m01
  • vec[2] * m02;

    vec[1] =

    vec[0] * m10
  • vec[1] * m11
  • vec[2] * m12;

    vec[2] =

    vec[0] * m20
  • vec[1] * m21
  • vec[2] * m22;

    }



    /**
  • <code>inverseRotate</code> uses the rotational part of
  • the matrix to rotate a vector in the opposite direction.
  • @param v the vector to rotate.
  • @return the rotated vector.

    */

    public Vector3f inverseRotate(Vector3f v) {

    Vector3f out = new Vector3f();

    out.x = v.x * m00 + v.y * m10 + v.z * m20;

    out.y = v.x * m01 + v.y * m11 + v.z * m21;

    out.z = v.x * m02 + v.y * m12 + v.z * m22;

    return out;

    }



    /**
  • <code>toString</code> returns the string representation of this object.
  • It is in a format of a 4x4 matrix. For example, an identity matrix would
  • be represented by the following string.
  • com.jme.math.Matrix3f<br>
  • [<br>
  • 1.0 0.0 0.0 0.0<br>
  • 0.0 1.0 0.0 0.0<br>
  • 0.0 0.0 1.0 0.0<br>
  • 0.0 0.0 0.0 1.0 <br>
  • ]<br>

    *
  • @return the string representation of this object.

    */

    public String toString() {

    String result = "com.jme.math.Matrixx4fn[n"+

    m00 + " " + m01 + " " + m02 + " " + m03+"n"+

    m10 + " " + m11 + " " + m12 + " " + m13+"n"+

    m20 + " " + m21 + " " + m22 + " " + m23+"n"+

    m30 + " " + m31 + " " + m32 + " " + m33+"n]";

    return result;

    }

    }

/**

  • TestMatrix intended to insure Matrix4f works same as Matrixx4f

    **/

    public class TestMatrix {

    static Random r=new Random();

    public static void main(String[] args) {

    Matrix4f jMEmat=new Matrix4f();

    Matrixx4f myMat=new Matrixx4f();

    float[] origValues=new float[16];

    float[] randVec=new float[4];

    Quaternion testQuat=new Quaternion();

    Vector3f testVec=new Vector3f();

    float[] fill3=new float[3];



    for (int i=0;i<1000;i++){

    fillRandom(origValues);

    fillRandom(randVec);

    fillRandom(fill3);

    myMat.set(origValues);

    jMEmat.set(origValues);



    testQuat.set(randVec[0],randVec[1],randVec[2],randVec[3]);

    myMat.set(testQuat);

    jMEmat.set(testQuat);

    test(jMEmat,myMat);

    myMat.setRotationQuaternion(testQuat);

    jMEmat.setRotationQuaternion(testQuat);

    test(jMEmat,myMat);



    testVec.set(randVec[0],randVec[1],randVec[2]);

    if (myMat.inverseRotate(testVec).distance(jMEmat.inverseRotate(testVec))>.0001){

    System.out.println("dang!");

    System.out.println(myMat.toString() + jMEmat.toString());

    System.exit(0);

    }

    jMEmat.angleRotation(testVec);

    myMat.angleRotation(testVec);

    test(jMEmat,myMat);

    jMEmat.setInverseRotationDegrees(fill3);

    myMat.setInverseRotationDegrees(fill3);

    test(jMEmat,myMat);

    System.out.println("Yes, it works!");

    }

    System.out.println(jMEmat);

    System.out.println(myMat);

    System.out.println("Everything checks out!");



    }



    private static void test(Matrix4f jMEmat, Matrixx4f myMat) {

    if (!equals(jMEmat,myMat)){

    System.out.println("Dang, not the same");

    System.out.println(jMEmat);

    System.out.println(myMat);

    System.exit(0);

    }

    }



    private static void fillRandom(float[] origValues) {

    for (int i=0;i<origValues.length;i++)

    origValues=r.nextFloat()*r.nextInt(100);

    }

    private static boolean equals(Matrix4f a,Matrixx4f b){

    for (int i=0;i<4;i++)

    for (int j=0;j<4;j++)

    if (!close(a.get(i,j),b.get(i,j))) return false;

    return true;

    }



    private static boolean close(float v, float v1) {

    return (Math.abs(v1-v) < .0001f);

    }

    }

Just make sure the milkshape loader runs and it’s either the same speed or faster.