/**
   * Pop the last Matrix4f from the stack and override the internal transform with the popped matrix
   * values. True if the stack size is greater than zero, false if the stack size is zero
   */
  public boolean popMatrix() {
    if (matrixStack.size() > 0) {
      Matrix4f m = matrixStack.get(matrixStack.size() - 1);

      matrixStack.remove(matrixStack.size() - 1);
      mM.A = m.A;
      mM.B = m.B;
      mM.C = m.C;
      mM.D = m.D;
      mM.E = m.E;
      mM.F = m.F;
      mM.G = m.G;
      mM.H = m.H;
      mM.I = m.I;
      mM.L = m.L;
      mM.M = m.M;
      mM.N = m.N;
      mM.O = m.O;
      mM.P = m.P;
      mM.Q = m.Q;
      mM.R = m.R;

      return (true);
    }
    return (false);
  }
  public static Transform3f GenerateProjectionToPlaneMatrix(
      Vertex3f f, Vertex3f pPos, Vertex3f pN) {

    Transform3f t = new Transform3f();

    /**
     * Proiezione sul piano...
     *
     * <p>P' e` l'intersezione del piano (P'-Q)N=0 con la retta P'=(F+t(P-F))
     *
     * <p>( F +t(P-F) -Q )N=0
     *
     * <p>-> t=(Q-F)N/(P-F)N
     *
     * <p>P'=F+(P-F)*t
     *
     * <p>Allora...
     *
     * <p>k=(Q-F)N
     *
     * <p>X'=(xf*W'+(x-xf)*k)/W' Y'=(yf*W'+(y-yf)*k)/W' Z'=(zf*W'+(z-zf)*k)/W' W'=P*N-F*N;
     *
     * <p>X'=(xf*(x+*xN+y*Yn+z*ZN-F*N)+(x-xf)*k)/W' Y'=(yf*(x+*xN+y*Yn+z*ZN-F*N)+(y-yf)*k)/W'
     * Z'=(zf*(x+*xN+y*Yn+z*ZN-F*N)+(z-zf)*k)/W'
     */
    float k =
        (pN.getX() * (pPos.getX() - f.getX())
            + pN.getY() * (pPos.getY() - f.getY())
            + pN.getZ() * (pPos.getZ() - f.getZ()));

    t.mM.O = pN.getX();
    t.mM.P = pN.getY();
    t.mM.Q = pN.getZ();
    t.mM.R = -(pN.getX() * f.getX() + pN.getY() * f.getY() + pN.getZ() * f.getZ());
    float fn = t.mM.R;

    // X'=(xf*(x+*xN+y*Yn+z*ZN-F*N)+(x-xf)*k)
    t.mM.A = f.getX() * (pN.getX()) + k;
    t.mM.B = f.getX() * (pN.getY());
    t.mM.C = f.getX() * (pN.getZ());
    t.mM.D = f.getX() * (fn - k);

    t.mM.E = f.getY() * (pN.getX());
    t.mM.F = f.getY() * (pN.getY()) + k;
    t.mM.G = f.getY() * (pN.getZ());
    t.mM.H = f.getY() * (fn - k);

    t.mM.I = f.getZ() * (pN.getX());
    t.mM.L = f.getZ() * (pN.getY());
    t.mM.M = f.getZ() * (pN.getZ()) + k;
    t.mM.N = f.getZ() * (fn - k);

    return (t);
  }
  /**
   * Multiply this Matrix for a Translation Matrix, where the vector (x,y,z) the translation entity
   */
  public void translate(float x, float y, float z) {

    Transform3f t = new Transform3f();

    t.mM.D = x;
    t.mM.H = y;
    t.mM.N = z;
    t.mM.R = 1;

    mult(t);
  }
 /** converts this matrix into an identity matrix */
 public void loadIdentity() {
   mM.A = 1;
   mM.B = 0;
   mM.C = 0;
   mM.D = 0;
   mM.E = 0;
   mM.F = 1;
   mM.G = 0;
   mM.H = 0;
   mM.I = 0;
   mM.L = 0;
   mM.M = 1;
   mM.N = 0;
   mM.O = 0;
   mM.P = 0;
   mM.Q = 0;
   mM.R = 1;
 }
  /** Push a copy of the actual Matrix4f on the internal matrix stack. */
  public void pushMatrix() {
    Matrix4f m = new Matrix4f();

    m.A = mM.A;
    m.B = mM.B;
    m.C = mM.C;
    m.D = mM.D;
    m.E = mM.E;
    m.F = mM.F;
    m.G = mM.G;
    m.H = mM.H;
    m.I = mM.I;
    m.L = mM.L;
    m.M = mM.M;
    m.N = mM.N;
    m.O = mM.O;
    m.P = mM.P;
    m.Q = mM.Q;
    m.R = mM.R;

    matrixStack.add(m);
  }
  /**
   * Multiply this Transform (M) with another transform t, so that M'=Mt and override this transorm
   * with the result
   */
  public void mult(Transform3f t) {

    float A = mM.A * t.mM.A + mM.B * t.mM.E + mM.C * t.mM.I + mM.D * t.mM.O;
    float B = mM.A * t.mM.B + mM.B * t.mM.F + mM.C * t.mM.L + mM.D * t.mM.P;
    float C = mM.A * t.mM.C + mM.B * t.mM.G + mM.C * t.mM.M + mM.D * t.mM.Q;
    float D = mM.A * t.mM.D + mM.B * t.mM.H + mM.C * t.mM.N + mM.D * t.mM.R;

    float E = mM.E * t.mM.A + mM.F * t.mM.E + mM.G * t.mM.I + mM.H * t.mM.O;
    float F = mM.E * t.mM.B + mM.F * t.mM.F + mM.G * t.mM.L + mM.H * t.mM.P;
    float G = mM.E * t.mM.C + mM.F * t.mM.G + mM.G * t.mM.M + mM.H * t.mM.Q;
    float H = mM.E * t.mM.D + mM.F * t.mM.H + mM.G * t.mM.N + mM.H * t.mM.R;

    float I = mM.I * t.mM.A + mM.L * t.mM.E + mM.M * t.mM.I + mM.N * t.mM.O;
    float L = mM.I * t.mM.B + mM.L * t.mM.F + mM.M * t.mM.L + mM.N * t.mM.P;
    float M = mM.I * t.mM.C + mM.L * t.mM.G + mM.M * t.mM.M + mM.N * t.mM.Q;
    float N = mM.I * t.mM.D + mM.L * t.mM.H + mM.M * t.mM.N + mM.N * t.mM.R;

    float O = mM.O * t.mM.A + mM.P * t.mM.E + mM.Q * t.mM.I + mM.R * t.mM.O;
    float P = mM.O * t.mM.B + mM.P * t.mM.F + mM.Q * t.mM.L + mM.R * t.mM.P;
    float Q = mM.O * t.mM.C + mM.P * t.mM.G + mM.Q * t.mM.M + mM.R * t.mM.Q;
    float R = mM.O * t.mM.D + mM.P * t.mM.H + mM.Q * t.mM.N + mM.R * t.mM.R;

    mM.A = A;
    mM.E = E;
    mM.I = I;
    mM.O = O;
    mM.B = B;
    mM.F = F;
    mM.L = L;
    mM.P = P;
    mM.C = C;
    mM.G = G;
    mM.M = M;
    mM.Q = Q;
    mM.D = D;
    mM.H = H;
    mM.N = N;
    mM.R = R;
  }