text: /**
   * @author       Richard Davey <rich@photonstorm.com>
   * @copyright    2022 Photon Storm Ltd.
   * @license      {@link https://opensource.org/licenses/MIT|MIT License}
   */
  
  var Class = require('../utils/Class');
  var Vector3 = require('./Vector3');
  
  /**
   * @ignore
   */
  var EPSILON = 0.000001;
  
  /**
   * @classdesc
   * A four-dimensional matrix.
   *
   * Adapted from [gl-matrix](https://github.com/toji/gl-matrix) by toji
   * and [vecmath](https://github.com/mattdesl/vecmath) by mattdesl
   *
   * @class Matrix4
   * @memberof Phaser.Math
   * @constructor
   * @since 3.0.0
   *
   * @param {Phaser.Math.Matrix4} [m] - Optional Matrix4 to copy values from.
   */
  var Matrix4 = new Class({
  
      initialize:
  
      function Matrix4 (m)
      {
          /**
           * The matrix values.
           *
           * @name Phaser.Math.Matrix4#val
           * @type {Float32Array}
           * @since 3.0.0
           */
          this.val = new Float32Array(16);
  
          if (m)
          {
              //  Assume Matrix4 with val:
              this.copy(m);
          }
          else
          {
              //  Default to identity
              this.identity();
          }
      },
  
      /**
       * Make a clone of this Matrix4.
       *
       * @method Phaser.Math.Matrix4#clone
       * @since 3.0.0
       *
       * @return {Phaser.Math.Matrix4} A clone of this Matrix4.
       */
      clone: function ()
      {
          return new Matrix4(this);
      },
  
      /**
       * This method is an alias for `Matrix4.copy`.
       *
       * @method Phaser.Math.Matrix4#set
       * @since 3.0.0
       *
       * @param {Phaser.Math.Matrix4} src - The Matrix to set the values of this Matrix's from.
       *
       * @return {this} This Matrix4.
       */
      set: function (src)
      {
          return this.copy(src);
      },
  
      /**
       * Sets all values of this Matrix4.
       *
       * @method Phaser.Math.Matrix4#setValues
       * @since 3.50.0
       *
       * @param {number} m00 - The m00 value.
       * @param {number} m01 - The m01 value.
       * @param {number} m02 - The m02 value.
       * @param {number} m03 - The m03 value.
       * @param {number} m10 - The m10 value.
       * @param {number} m11 - The m11 value.
       * @param {number} m12 - The m12 value.
       * @param {number} m13 - The m13 value.
       * @param {number} m20 - The m20 value.
       * @param {number} m21 - The m21 value.
       * @param {number} m22 - The m22 value.
       * @param {number} m23 - The m23 value.
       * @param {number} m30 - The m30 value.
       * @param {number} m31 - The m31 value.
       * @param {number} m32 - The m32 value.
       * @param {number} m33 - The m33 value.
       *
       * @return {this} This Matrix4 instance.
       */
      setValues: function (m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33)
      {
          var out = this.val;
  
          out[0] = m00;
          out[1] = m01;
          out[2] = m02;
          out[3] = m03;
          out[4] = m10;
          out[5] = m11;
          out[6] = m12;
          out[7] = m13;
          out[8] = m20;
          out[9] = m21;
          out[10] = m22;
          out[11] = m23;
          out[12] = m30;
          out[13] = m31;
          out[14] = m32;
          out[15] = m33;
  
          return this;
      },
  
      /**
       * Copy the values of a given Matrix into this Matrix.
       *
       * @method Phaser.Math.Matrix4#copy
       * @since 3.0.0
       *
       * @param {Phaser.Math.Matrix4} src - The Matrix to copy the values from.
       *
       * @return {this} This Matrix4.
       */
      copy: function (src)
      {
          var a = src.val;
  
          return this.setValues(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
      },
  
      /**
       * Set the values of this Matrix from the given array.
       *
       * @method Phaser.Math.Matrix4#fromArray
       * @since 3.0.0
       *
       * @param {number[]} a - The array to copy the values from. Must have at least 16 elements.
       *
       * @return {this} This Matrix4.
       */
      fromArray: function (a)
      {
          return this.setValues(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
      },
  
      /**
       * Reset this Matrix.
       *
       * Sets all values to `0`.
       *
       * @method Phaser.Math.Matrix4#zero
       * @since 3.0.0
       *
       * @return {Phaser.Math.Matrix4} This Matrix4.
       */
      zero: function ()
      {
          return this.setValues(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      },
  
      /**
       * Generates a transform matrix based on the given position, scale and rotation.
       *
       * @method Phaser.Math.Matrix4#transform
       * @since 3.50.0
       *
       * @param {Phaser.Math.Vector3} position - The position vector.
       * @param {Phaser.Math.Vector3} scale - The scale vector.
       * @param {Phaser.Math.Quaternion} rotation - The rotation quaternion.
       *
       * @return {this} This Matrix4.
       */
      transform: function (position, scale, rotation)
      {
          var rotMatrix = _tempMat1.fromQuat(rotation);
  
          var rm = rotMatrix.val;
  
          var sx = scale.x;
          var sy = scale.y;
          var sz = scale.z;
  
          return this.setValues(
              rm[0] * sx,
              rm[1] * sx,
              rm[2] * sx,
              0,
  
              rm[4] * sy,
              rm[5] * sy,
              rm[6] * sy,
              0,
  
              rm[8] * sz,
              rm[9] * sz,
              rm[10] * sz,
              0,
  
              position.x,
              position.y,
              position.z,
              1
          );
      },
  
      /**
       * Set the `x`, `y` and `z` values of this Matrix.
       *
       * @method Phaser.Math.Matrix4#xyz
       * @since 3.0.0
       *
       * @param {number} x - The x value.
       * @param {number} y - The y value.
       * @param {number} z - The z value.
       *
       * @return {this} This Matrix4.
       */
      xyz: function (x, y, z)
      {
          this.identity();
  
          var out = this.val;
  
          out[12] = x;
          out[13] = y;
          out[14] = z;
  
          return this;
      },
  
      /**
       * Set the scaling values of this Matrix.
       *
       * @method Phaser.Math.Matrix4#scaling
       * @since 3.0.0
       *
       * @param {number} x - The x scaling value.
       * @param {number} y - The y scaling value.
       * @param {number} z - The z scaling value.
       *
       * @return {this} This Matrix4.
       */
      scaling: function (x, y, z)
      {
          this.zero();
  
          var out = this.val;
  
          out[0] = x;
          out[5] = y;
          out[10] = z;
          out[15] = 1;
  
          return this;
      },
  
      /**
       * Reset this Matrix to an identity (default) matrix.
       *
       * @method Phaser.Math.Matrix4#identity
       * @since 3.0.0
       *
       * @return {this} This Matrix4.
       */
      identity: function ()
      {
          return this.setValues(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
      },
  
      /**
       * Transpose this Matrix.
       *
       * @method Phaser.Math.Matrix4#transpose
       * @since 3.0.0
       *
       * @return {this} This Matrix4.
       */
      transpose: function ()
      {
          var a = this.val;
  
          var a01 = a[1];
          var a02 = a[2];
          var a03 = a[3];
          var a12 = a[6];
          var a13 = a[7];
          var a23 = a[11];
  
          a[1] = a[4];
          a[2] = a[8];
          a[3] = a[12];
          a[4] = a01;
          a[6] = a[9];
          a[7] = a[13];
          a[8] = a02;
          a[9] = a12;
          a[11] = a[14];
          a[12] = a03;
          a[13] = a13;
          a[14] = a23;
  
          return this;
      },
  
      /**
       * Copies the given Matrix4 into this Matrix and then inverses it.
       *
       * @method Phaser.Math.Matrix4#getInverse
       * @since 3.50.0
       *
       * @param {Phaser.Math.Matrix4} m - The Matrix4 to invert into this Matrix4.
       *
       * @return {this} This Matrix4.
       */
      getInverse: function (m)
      {
          this.copy(m);
  
          return this.invert();
      },
  
      /**
       * Invert this Matrix.
       *
       * @method Phaser.Math.Matrix4#invert
       * @since 3.0.0
       *
       * @return {this} This Matrix4.
       */
      invert: function ()
      {
          var a = this.val;
  
          var a00 = a[0];
          var a01 = a[1];
          var a02 = a[2];
          var a03 = a[3];
  
          var a10 = a[4];
          var a11 = a[5];
          var a12 = a[6];
          var a13 = a[7];
  
          var a20 = a[8];
          var a21 = a[9];
          var a22 = a[10];
          var a23 = a[11];
  
          var a30 = a[12];
          var a31 = a[13];
          var a32 = a[14];
          var a33 = a[15];
  
          var b00 = a00 * a11 - a01 * a10;
          var b01 = a00 * a12 - a02 * a10;
          var b02 = a00 * a13 - a03 * a10;
          var b03 = a01 * a12 - a02 * a11;
  
          var b04 = a01 * a13 - a03 * a11;
          var b05 = a02 * a13 - a03 * a12;
          var b06 = a20 * a31 - a21 * a30;
          var b07 = a20 * a32 - a22 * a30;
  
          var b08 = a20 * a33 - a23 * a30;
          var b09 = a21 * a32 - a22 * a31;
          var b10 = a21 * a33 - a23 * a31;
          var b11 = a22 * a33 - a23 * a32;
  
          //  Calculate the determinant
          var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
  
          if (!det)
          {
              return this;
          }
  
          det = 1 / det;
  
          return this.setValues(
              (a11 * b11 - a12 * b10 + a13 * b09) * det,
              (a02 * b10 - a01 * b11 - a03 * b09) * det,
              (a31 * b05 - a32 * b04 + a33 * b03) * det,
              (a22 * b04 - a21 * b05 - a23 * b03) * det,
              (a12 * b08 - a10 * b11 - a13 * b07) * det,
              (a00 * b11 - a02 * b08 + a03 * b07) * det,
              (a32 * b02 - a30 * b05 - a33 * b01) * det,
              (a20 * b05 - a22 * b02 + a23 * b01) * det,
              (a10 * b10 - a11 * b08 + a13 * b06) * det,
              (a01 * b08 - a00 * b10 - a03 * b06) * det,
              (a30 * b04 - a31 * b02 + a33 * b00) * det,
              (a21 * b02 - a20 * b04 - a23 * b00) * det,
              (a11 * b07 - a10 * b09 - a12 * b06) * det,
              (a00 * b09 - a01 * b07 + a02 * b06) * det,
              (a31 * b01 - a30 * b03 - a32 * b00) * det,
              (a20 * b03 - a21 * b01 + a22 * b00) * det
          );
      },
  
      /**
       * Calculate the adjoint, or adjugate, of this Matrix.
       *
       * @method Phaser.Math.Matrix4#adjoint
       * @since 3.0.0
       *
       * @return {this} This Matrix4.
       */
      adjoint: function ()
      {
          var a = this.val;
  
          var a00 = a[0];
          var a01 = a[1];
          var a02 = a[2];
          var a03 = a[3];
  
          var a10 = a[4];
          var a11 = a[5];
          var a12 = a[6];
          var a13 = a[7];
  
          var a20 = a[8];
          var a21 = a[9];
          var a22 = a[10];
          var a23 = a[11];
  
          var a30 = a[12];
          var a31 = a[13];
          var a32 = a[14];
          var a33 = a[15];
  
          return this.setValues(
              (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22)),
              -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)),
              (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12)),
              -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)),
              -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)),
              (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22)),
              -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)),
              (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12)),
              (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21)),
              -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)),
              (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11)),
              -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)),
              -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)),
              (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21)),
              -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)),
              (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11))
          );
      },
  
      /**
       * Calculate the determinant of this Matrix.
       *
       * @method Phaser.Math.Matrix4#determinant
       * @since 3.0.0
       *
       * @return {number} The determinant of this Matrix.
       */
      determinant: function ()
      {
          var a = this.val;
  
          var a00 = a[0];
          var a01 = a[1];
          var a02 = a[2];
          var a03 = a[3];
  
          var a10 = a[4];
          var a11 = a[5];
          var a12 = a[6];
          var a13 = a[7];
  
          var a20 = a[8];
          var a21 = a[9];
          var a22 = a[10];
          var a23 = a[11];
  
          var a30 = a[12];
          var a31 = a[13];
          var a32 = a[14];
          var a33 = a[15];
  
          var b00 = a00 * a11 - a01 * a10;
          var b01 = a00 * a12 - a02 * a10;
          var b02 = a00 * a13 - a03 * a10;
          var b03 = a01 * a12 - a02 * a11;
          var b04 = a01 * a13 - a03 * a11;
          var b05 = a02 * a13 - a03 * a12;
          var b06 = a20 * a31 - a21 * a30;
          var b07 = a20 * a32 - a22 * a30;
          var b08 = a20 * a33 - a23 * a30;
          var b09 = a21 * a32 - a22 * a31;
          var b10 = a21 * a33 - a23 * a31;
          var b11 = a22 * a33 - a23 * a32;
  
          // Calculate the determinant
          return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
      },
  
      /**
       * Multiply this Matrix by the given Matrix.
       *
       * @method Phaser.Math.Matrix4#multiply
       * @since 3.0.0
       *
       * @param {Phaser.Math.Matrix4} src - The Matrix to multiply this Matrix by.
       *
       * @return {this} This Matrix4.
       */
      multiply: function (src)
      {
          var a = this.val;
  
          var a00 = a[0];
          var a01 = a[1];
          var a02 = a[2];
          var a03 = a[3];
  
          var a10 = a[4];
          var a11 = a[5];
          var a12 = a[6];
          var a13 = a[7];
  
          var a20 = a[8];
          var a21 = a[9];
          var a22 = a[10];
          var a23 = a[11];
  
          var a30 = a[12];
          var a31 = a[13];
          var a32 = a[14];
          var a33 = a[15];
  
          var b = src.val;
  
          // Cache only the current line of the second matrix
          var b0 = b[0];
          var b1 = b[1];
          var b2 = b[2];
          var b3 = b[3];
  
          a[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
          a[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
          a[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
          a[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
  
          b0 = b[4];
          b1 = b[5];
          b2 = b[6];
          b3 = b[7];
  
          a[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
          a[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
          a[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
          a[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
  
          b0 = b[8];
          b1 = b[9];
          b2 = b[10];
          b3 = b[11];
  
          a[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
          a[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
          a[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
          a[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
  
          b0 = b[12];
          b1 = b[13];
          b2 = b[14];
          b3 = b[15];
  
          a[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
          a[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
          a[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
          a[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
  
          return this;
      },
  
      /**
       * Multiply the values of this Matrix4 by those given in the `src` argument.
       *
       * @method Phaser.Math.Matrix4#multiplyLocal
       * @since 3.0.0
       *
       * @param {Phaser.Math.Matrix4} src - The source Matrix4 that this Matrix4 is multiplied by.
       *
       * @return {this} This Matrix4.
       */
      multiplyLocal: function (src)
      {
          var a = this.val;
          var b = src.val;
  
          return this.setValues(
              a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12],
              a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13],
              a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14],
              a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15],
  
              a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12],
              a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13],
              a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14],
              a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15],
  
              a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12],
              a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13],
              a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14],
              a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15],
  
              a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12],
              a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13],
              a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14],
              a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15]
          );
      },
  
      /**
       * Multiplies the given Matrix4 object with this Matrix.
       *
       * This is the same as calling `multiplyMatrices(m, this)`.
       *
       * @method Phaser.Math.Matrix4#premultiply
       * @since 3.50.0
       *
       * @param {Phaser.Math.Matrix4} m - The Matrix4 to multiply with this one.
       *
       * @return {this} This Matrix4.
       */
      premultiply: function (m)
      {
          return this.multiplyMatrices(m, this);
      },
  
      /**
       * Multiplies the two given Matrix4 objects and stores the results in this Matrix.
       *
       * @method Phaser.Math.Matrix4#multiplyMatrices
       * @since 3.50.0
       *
       * @param {Phaser.Math.Matrix4} a - The first Matrix4 to multiply.
       * @param {Phaser.Math.Matrix4} b - The second Matrix4 to multiply.
       *
       * @return {this} This Matrix4.
       */
      multiplyMatrices: function (a, b)
      {
          var am = a.val;
          var bm = b.val;
  
          var a11 = am[0];
          var a12 = am[4];
          var a13 = am[8];
          var a14 = am[12];
          var a21 = am[1];
          var a22 = am[5];
          var a23 = am[9];
          var a24 = am[13];
          var a31 = am[2];
          var a32 = am[6];
          var a33 = am[10];
          var a34 = am[14];
          var a41 = am[3];
          var a42 = am[7];
          var a43 = am[11];
          var a44 = am[15];
  
          var b11 = bm[0];
          var b12 = bm[4];
          var b13 = bm[8];
          var b14 = bm[12];
          var b21 = bm[1];
          var b22 = bm[5];
          var b23 = bm[9];
          var b24 = bm[13];
          var b31 = bm[2];
          var b32 = bm[6];
          var b33 = bm[10];
          var b34 = bm[14];
          var b41 = bm[3];
          var b42 = bm[7];
          var b43 = bm[11];
          var b44 = bm[15];
  
          return this.setValues(
              a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41,
              a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41,
              a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41,
              a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41,
              a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42,
              a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42,
              a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42,
              a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42,
              a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43,
              a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43,
              a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43,
              a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43,
              a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44,
              a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44,
              a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44,
              a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44
          );
      },
  
      /**
       * Translate this Matrix using the given Vector.
       *
       * @method Phaser.Math.Matrix4#translate
       * @since 3.0.0
       *
       * @param {(Phaser.Math.Vector3|Phaser.Math.Vector4)} v - The Vector to translate this Matrix with.
       *
       * @return {this} This Matrix4.
       */
      translate: function (v)
      {
          return this.translateXYZ(v.x, v.y, v.z);
      },
  
      /**
       * Translate this Matrix using the given values.
       *
       * @method Phaser.Math.Matrix4#translateXYZ
       * @since 3.16.0
       *
       * @param {number} x - The x component.
       * @param {number} y - The y component.
       * @param {number} z - The z component.
       *
       * @return {this} This Matrix4.
       */
      translateXYZ: function (x, y, z)
      {
          var a = this.val;
  
          a[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
          a[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
          a[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
          a[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
  
          return this;
      },
  
      /**
       * Apply a scale transformation to this Matrix.
       *
       * Uses the `x`, `y` and `z` components of the given Vector to scale the Matrix.
       *
       * @method Phaser.Math.Matrix4#scale
       * @since 3.0.0
       *
       * @param {(Phaser.Math.Vector3|Phaser.Math.Vector4)} v - The Vector to scale this Matrix with.
       *
       * @return {this} This Matrix4.
       */
      scale: function (v)
      {
          return this.scaleXYZ(v.x, v.y, v.z);
      },
  
      /**
       * Apply a scale transformation to this Matrix.
       *
       * @method Phaser.Math.Matrix4#scaleXYZ
       * @since 3.16.0
       *
       * @param {number} x - The x component.
       * @param {number} y - The y component.
       * @param {number} z - The z component.
       *
       * @return {this} This Matrix4.
       */
      scaleXYZ: function (x, y, z)
      {
          var a = this.val;
  
          a[0] = a[0] * x;
          a[1] = a[1] * x;
          a[2] = a[2] * x;
          a[3] = a[3] * x;
  
          a[4] = a[4] * y;
          a[5] = a[5] * y;
          a[6] = a[6] * y;
          a[7] = a[7] * y;
  
          a[8] = a[8] * z;
          a[9] = a[9] * z;
          a[10] = a[10] * z;
          a[11] = a[11] * z;
  
          return this;
      },
  
      /**
       * Derive a rotation matrix around the given axis.
       *
       * @method Phaser.Math.Matrix4#makeRotationAxis
       * @since 3.0.0
       *
       * @param {(Phaser.Math.Vector3|Phaser.Math.Vector4)} axis - The rotation axis.
       * @param {number} angle - The rotation angle in radians.
       *
       * @return {this} This Matrix4.
       */
      makeRotationAxis: function (axis, angle)
      {
          // Based on http://www.gamedev.net/reference/articles/article1199.asp
  
          var c = Math.cos(angle);
          var s = Math.sin(angle);
          var t = 1 - c;
          var x = axis.x;
          var y = axis.y;
          var z = axis.z;
          var tx = t * x;
          var ty = t * y;
  
          return this.setValues(
              tx * x + c, tx * y - s * z, tx * z + s * y, 0,
              tx * y + s * z, ty * y + c, ty * z - s * x, 0,
              tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
              0, 0, 0, 1
          );
      },
  
      /**
       * Apply a rotation transformation to this Matrix.
       *
       * @method Phaser.Math.Matrix4#rotate
       * @since 3.0.0
       *
       * @param {number} rad - The angle in radians to rotate by.
       * @param {Phaser.Math.Vector3} axis - The axis to rotate upon.
       *
       * @return {this} This Matrix4.
       */
      rotate: function (rad, axis)
      {
          var a = this.val;
          var x = axis.x;
          var y = axis.y;
          var z = axis.z;
          var len = Math.sqrt(x * x + y * y + z * z);
  
          if (Math.abs(len) < EPSILON)
          {
              return this;
          }
  
          len = 1 / len;
          x *= len;
          y *= len;
          z *= len;
  
          var s = Math.sin(rad);
          var c = Math.cos(rad);
          var t = 1 - c;
  
          var a00 = a[0];
          var a01 = a[1];
          var a02 = a[2];
          var a03 = a[3];
  
          var a10 = a[4];
          var a11 = a[5];
          var a12 = a[6];
          var a13 = a[7];
  
          var a20 = a[8];
          var a21 = a[9];
          var a22 = a[10];
          var a23 = a[11];
  
          var a30 = a[12];
          var a31 = a[13];
          var a32 = a[14];
          var a33 = a[15];
  
          //  Construct the elements of the rotation matrix
          var b00 = x * x * t + c;
          var b01 = y * x * t + z * s;
          var b02 = z * x * t - y * s;
  
          var b10 = x * y * t - z * s;
          var b11 = y * y * t + c;
          var b12 = z * y * t + x * s;
  
          var b20 = x * z * t + y * s;
          var b21 = y * z * t - x * s;
          var b22 = z * z * t + c;
  
          //  Perform rotation-specific matrix multiplication
          return this.setValues(
              a00 * b00 + a10 * b01 + a20 * b02,
              a01 * b00 + a11 * b01 + a21 * b02,
              a02 * b00 + a12 * b01 + a22 * b02,
              a03 * b00 + a13 * b01 + a23 * b02,
              a00 * b10 + a10 * b11 + a20 * b12,
              a01 * b10 + a11 * b11 + a21 * b12,
              a02 * b10 + a12 * b11 + a22 * b12,
              a03 * b10 + a13 * b11 + a23 * b12,
              a00 * b20 + a10 * b21 + a20 * b22,
              a01 * b20 + a11 * b21 + a21 * b22,
              a02 * b20 + a12 * b21 + a22 * b22,
              a03 * b20 + a13 * b21 + a23 * b22,
              a30, a31, a32, a33
          );
      },
  
      /**
       * Rotate this matrix on its X axis.
       *
       * @method Phaser.Math.Matrix4#rotateX
       * @since 3.0.0
       *
       * @param {number} rad - The angle in radians to rotate by.
       *
       * @return {this} This Matrix4.
       */
      rotateX: function (rad)
      {
          var a = this.val;
          var s = Math.sin(rad);
          var c = Math.cos(rad);
  
          var a10 = a[4];
          var a11 = a[5];
          var a12 = a[6];
          var a13 = a[7];
  
          var a20 = a[8];
          var a21 = a[9];
          var a22 = a[10];
          var a23 = a[11];
  
          //  Perform axis-specific matrix multiplication
          a[4] = a10 * c + a20 * s;
          a[5] = a11 * c + a21 * s;
          a[6] = a12 * c + a22 * s;
          a[7] = a13 * c + a23 * s;
          a[8] = a20 * c - a10 * s;
          a[9] = a21 * c - a11 * s;
          a[10] = a22 * c - a12 * s;
          a[11] = a23 * c - a13 * s;
  
          return this;
      },
  
      /**
       * Rotate this matrix on its Y axis.
       *
       * @method Phaser.Math.Matrix4#rotateY
       * @since 3.0.0
       *
       * @param {number} rad - The angle to rotate by, in radians.
       *
       * @return {this} This Matrix4.
       */
      rotateY: function (rad)
      {
          var a = this.val;
          var s = Math.sin(rad);
          var c = Math.cos(rad);
  
          var a00 = a[0];
          var a01 = a[1];
          var a02 = a[2];
          var a03 = a[3];
  
          var a20 = a[8];
          var a21 = a[9];
          var a22 = a[10];
          var a23 = a[11];
  
          //  Perform axis-specific matrix multiplication
          a[0] = a00 * c - a20 * s;
          a[1] = a01 * c - a21 * s;
          a[2] = a02 * c - a22 * s;
          a[3] = a03 * c - a23 * s;
          a[8] = a00 * s + a20 * c;
          a[9] = a01 * s + a21 * c;
          a[10] = a02 * s + a22 * c;
          a[11] = a03 * s + a23 * c;
  
          return this;
      },
  
      /**
       * Rotate this matrix on its Z axis.
       *
       * @method Phaser.Math.Matrix4#rotateZ
       * @since 3.0.0
       *
       * @param {number} rad - The angle to rotate by, in radians.
       *
       * @return {this} This Matrix4.
       */
      rotateZ: function (rad)
      {
          var a = this.val;
          var s = Math.sin(rad);
          var c = Math.cos(rad);
  
          var a00 = a[0];
          var a01 = a[1];
          var a02 = a[2];
          var a03 = a[3];
  
          var a10 = a[4];
          var a11 = a[5];
          var a12 = a[6];
          var a13 = a[7];
  
          //  Perform axis-specific matrix multiplication
          a[0] = a00 * c + a10 * s;
          a[1] = a01 * c + a11 * s;
          a[2] = a02 * c + a12 * s;
          a[3] = a03 * c + a13 * s;
          a[4] = a10 * c - a00 * s;
          a[5] = a11 * c - a01 * s;
          a[6] = a12 * c - a02 * s;
          a[7] = a13 * c - a03 * s;
  
          return this;
      },
  
      /**
       * Set the values of this Matrix from the given rotation Quaternion and translation Vector.
       *
       * @method Phaser.Math.Matrix4#fromRotationTranslation
       * @since 3.0.0
       *
       * @param {Phaser.Math.Quaternion} q - The Quaternion to set rotation from.
       * @param {Phaser.Math.Vector3} v - The Vector to set translation from.
       *
       * @return {this} This Matrix4.
       */
      fromRotationTranslation: function (q, v)
      {
          //  Quaternion math
          var x = q.x;
          var y = q.y;
          var z = q.z;
          var w = q.w;
  
          var x2 = x + x;
          var y2 = y + y;
          var z2 = z + z;
  
          var xx = x * x2;
          var xy = x * y2;
          var xz = x * z2;
  
          var yy = y * y2;
          var yz = y * z2;
          var zz = z * z2;
  
          var wx = w * x2;
          var wy = w * y2;
          var wz = w * z2;
  
          return this.setValues(
              1 - (yy + zz),
              xy + wz,
              xz - wy,
              0,
  
              xy - wz,
              1 - (xx + zz),
              yz + wx,
              0,
  
              xz + wy,
              yz - wx,
              1 - (xx + yy),
              0,
  
              v.x,
              v.y,
              v.z,
              1
          );
      },
  
      /**
       * Set the values of this Matrix from the given Quaternion.
       *
       * @method Phaser.Math.Matrix4#fromQuat
       * @since 3.0.0
       *
       * @param {Phaser.Math.Quaternion} q - The Quaternion to set the values of this Matrix from.
       *
       * @return {this} This Matrix4.
       */
      fromQuat: function (q)
      {
          var x = q.x;
          var y = q.y;
          var z = q.z;
          var w = q.w;
  
          var x2 = x + x;
          var y2 = y + y;
          var z2 = z + z;
  
          var xx = x * x2;
          var xy = x * y2;
          var xz = x * z2;
  
          var yy = y * y2;
          var yz = y * z2;
          var zz = z * z2;
  
          var wx = w * x2;
          var wy = w * y2;
          var wz = w * z2;
  
          return this.setValues(
              1 - (yy + zz),
              xy + wz,
              xz - wy,
              0,
  
              xy - wz,
              1 - (xx + zz),
              yz + wx,
              0,
  
              xz + wy,
              yz - wx,
              1 - (xx + yy),
              0,
  
              0,
              0,
              0,
              1
          );
      },
  
      /**
       * Generate a frustum matrix with the given bounds.
       *
       * @method Phaser.Math.Matrix4#frustum
       * @since 3.0.0
       *
       * @param {number} left - The left bound of the frustum.
       * @param {number} right - The right bound of the frustum.
       * @param {number} bottom - The bottom bound of the frustum.
       * @param {number} top - The top bound of the frustum.
       * @param {number} near - The near bound of the frustum.
       * @param {number} far - The far bound of the frustum.
       *
       * @return {this} This Matrix4.
       */
      frustum: function (left, right, bottom, top, near, far)
      {
          var rl = 1 / (right - left);
          var tb = 1 / (top - bottom);
          var nf = 1 / (near - far);
  
          return this.setValues(
              (near * 2) * rl,
              0,
              0,
              0,
  
              0,
              (near * 2) * tb,
              0,
              0,
  
              (right + left) * rl,
              (top + bottom) * tb,
              (far + near) * nf,
              -1,
  
              0,
              0,
              (far * near * 2) * nf,
              0
          );
      },
  
      /**
       * Generate a perspective projection matrix with the given bounds.
       *
       * @method Phaser.Math.Matrix4#perspective
       * @since 3.0.0
       *
       * @param {number} fovy - Vertical field of view in radians
       * @param {number} aspect - Aspect ratio. Typically viewport width  /height.
       * @param {number} near - Near bound of the frustum.
       * @param {number} far - Far bound of the frustum.
       *
       * @return {this} This Matrix4.
       */
      perspective: function (fovy, aspect, near, far)
      {
          var f = 1.0 / Math.tan(fovy / 2);
          var nf = 1 / (near - far);
  
          return this.setValues(
              f / aspect,
              0,
              0,
              0,
  
              0,
              f,
              0,
              0,
  
              0,
              0,
              (far + near) * nf,
              -1,
  
              0,
              0,
              (2 * far * near) * nf,
              0
          );
      },
  
      /**
       * Generate a perspective projection matrix with the given bounds.
       *
       * @method Phaser.Math.Matrix4#perspectiveLH
       * @since 3.0.0
       *
       * @param {number} width - The width of the frustum.
       * @param {number} height - The height of the frustum.
       * @param {number} near - Near bound of the frustum.
       * @param {number} far - Far bound of the frustum.
       *
       * @return {this} This Matrix4.
       */
      perspectiveLH: function (width, height, near, far)
      {
          return this.setValues(
              (2 * near) / width,
              0,
              0,
              0,
  
              0,
              (2 * near) / height,
              0,
              0,
  
              0,
              0,
              -far / (near - far),
              1,
  
              0,
              0,
              (near * far) / (near - far),
              0
          );
      },
  
      /**
       * Generate an orthogonal projection matrix with the given bounds.
       *
       * @method Phaser.Math.Matrix4#ortho
       * @since 3.0.0
       *
       * @param {number} left - The left bound of the frustum.
       * @param {number} right - The right bound of the frustum.
       * @param {number} bottom - The bottom bound of the frustum.
       * @param {number} top - The top bound of the frustum.
       * @param {number} near - The near bound of the frustum.
       * @param {number} far - The far bound of the frustum.
       *
       * @return {this} This Matrix4.
       */
      ortho: function (left, right, bottom, top, near, far)
      {
          var lr = left - right;
          var bt = bottom - top;
          var nf = near - far;
  
          //  Avoid division by zero
          lr = (lr === 0) ? lr : 1 / lr;
          bt = (bt === 0) ? bt : 1 / bt;
          nf = (nf === 0) ? nf : 1 / nf;
  
          return this.setValues(
              -2 * lr,
              0,
              0,
              0,
  
              0,
              -2 * bt,
              0,
              0,
  
              0,
              0,
              2 * nf,
              0,
  
              (left + right) * lr,
              (top + bottom) * bt,
              (far + near) * nf,
              1
          );
      },
  
      /**
       * Generate a right-handed look-at matrix with the given eye position, target and up axis.
       *
       * @method Phaser.Math.Matrix4#lookAtRH
       * @since 3.50.0
       *
       * @param {Phaser.Math.Vector3} eye - Position of the viewer.
       * @param {Phaser.Math.Vector3} target - Point the viewer is looking at.
       * @param {Phaser.Math.Vector3} up - vec3 pointing up.
       *
       * @return {this} This Matrix4.
       */
      lookAtRH: function (eye, target, up)
      {
          var m = this.val;
  
          _z.subVectors(eye, target);
  
          if (_z.getLengthSquared() === 0)
          {
              // eye and target are in the same position
              _z.z = 1;
          }
  
          _z.normalize();
          _x.crossVectors(up, _z);
  
          if (_x.getLengthSquared() === 0)
          {
              // up and z are parallel
  
              if (Math.abs(up.z) === 1)
              {
                  _z.x += 0.0001;
              }
              else
              {
                  _z.z += 0.0001;
              }
  
              _z.normalize();
              _x.crossVectors(up, _z);
          }
  
          _x.normalize();
          _y.crossVectors(_z, _x);
  
          m[0] = _x.x;
          m[1] = _x.y;
          m[2] = _x.z;
          m[4] = _y.x;
          m[5] = _y.y;
          m[6] = _y.z;
          m[8] = _z.x;
          m[9] = _z.y;
          m[10] = _z.z;
  
          return this;
      },
  
      /**
       * Generate a look-at matrix with the given eye position, focal point, and up axis.
       *
       * @method Phaser.Math.Matrix4#lookAt
       * @since 3.0.0
       *
       * @param {Phaser.Math.Vector3} eye - Position of the viewer
       * @param {Phaser.Math.Vector3} center - Point the viewer is looking at
       * @param {Phaser.Math.Vector3} up - vec3 pointing up.
       *
       * @return {this} This Matrix4.
       */
      lookAt: function (eye, center, up)
      {
          var eyex = eye.x;
          var eyey = eye.y;
          var eyez = eye.z;
  
          var upx = up.x;
          var upy = up.y;
          var upz = up.z;
  
          var centerx = center.x;
          var centery = center.y;
          var centerz = center.z;
  
          if (Math.abs(eyex - centerx) < EPSILON &&
              Math.abs(eyey - centery) < EPSILON &&
              Math.abs(eyez - centerz) < EPSILON)
          {
              return this.identity();
          }
  
          var z0 = eyex - centerx;
          var z1 = eyey - centery;
          var z2 = eyez - centerz;
  
          var len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
  
          z0 *= len;
          z1 *= len;
          z2 *= len;
  
          var x0 = upy * z2 - upz * z1;
          var x1 = upz * z0 - upx * z2;
          var x2 = upx * z1 - upy * z0;
  
          len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
  
          if (!len)
          {
              x0 = 0;
              x1 = 0;
              x2 = 0;
          }
          else
          {
              len = 1 / len;
              x0 *= len;
              x1 *= len;
              x2 *= len;
          }
  
          var y0 = z1 * x2 - z2 * x1;
          var y1 = z2 * x0 - z0 * x2;
          var y2 = z0 * x1 - z1 * x0;
  
          len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
  
          if (!len)
          {
              y0 = 0;
              y1 = 0;
              y2 = 0;
          }
          else
          {
              len = 1 / len;
              y0 *= len;
              y1 *= len;
              y2 *= len;
          }
  
          return this.setValues(
              x0,
              y0,
              z0,
              0,
  
              x1,
              y1,
              z1,
              0,
  
              x2,
              y2,
              z2,
              0,
  
              -(x0 * eyex + x1 * eyey + x2 * eyez),
              -(y0 * eyex + y1 * eyey + y2 * eyez),
              -(z0 * eyex + z1 * eyey + z2 * eyez),
              1
          );
      },
  
      /**
       * Set the values of this matrix from the given `yaw`, `pitch` and `roll` values.
       *
       * @method Phaser.Math.Matrix4#yawPitchRoll
       * @since 3.0.0
       *
       * @param {number} yaw - The yaw value.
       * @param {number} pitch - The pitch value.
       * @param {number} roll - The roll value.
       *
       * @return {this} This Matrix4.
       */
      yawPitchRoll: function (yaw, pitch, roll)
      {
          this.zero();
          _tempMat1.zero();
          _tempMat2.zero();
  
          var m0 = this.val;
          var m1 = _tempMat1.val;
          var m2 = _tempMat2.val;
  
          //  Rotate Z
          var s = Math.sin(roll);
          var c = Math.cos(roll);
  
          m0[10] = 1;
          m0[15] = 1;
          m0[0] = c;
          m0[1] = s;
          m0[4] = -s;
          m0[5] = c;
  
          //  Rotate X
          s = Math.sin(pitch);
          c = Math.cos(pitch);
  
          m1[0] = 1;
          m1[15] = 1;
          m1[5] = c;
          m1[10] = c;
          m1[9] = -s;
          m1[6] = s;
  
          //  Rotate Y
          s = Math.sin(yaw);
          c = Math.cos(yaw);
  
          m2[5] = 1;
          m2[15] = 1;
          m2[0] = c;
          m2[2] = -s;
          m2[8] = s;
          m2[10] = c;
  
          this.multiplyLocal(_tempMat1);
          this.multiplyLocal(_tempMat2);
  
          return this;
      },
  
      /**
       * Generate a world matrix from the given rotation, position, scale, view matrix and projection matrix.
       *
       * @method Phaser.Math.Matrix4#setWorldMatrix
       * @since 3.0.0
       *
       * @param {Phaser.Math.Vector3} rotation - The rotation of the world matrix.
       * @param {Phaser.Math.Vector3} position - The position of the world matrix.
       * @param {Phaser.Math.Vector3} scale - The scale of the world matrix.
       * @param {Phaser.Math.Matrix4} [viewMatrix] - The view matrix.
       * @param {Phaser.Math.Matrix4} [projectionMatrix] - The projection matrix.
       *
       * @return {this} This Matrix4.
       */
      setWorldMatrix: function (rotation, position, scale, viewMatrix, projectionMatrix)
      {
          this.yawPitchRoll(rotation.y, rotation.x, rotation.z);
  
          _tempMat1.scaling(scale.x, scale.y, scale.z);
          _tempMat2.xyz(position.x, position.y, position.z);
  
          this.multiplyLocal(_tempMat1);
          this.multiplyLocal(_tempMat2);
  
          if (viewMatrix)
          {
              this.multiplyLocal(viewMatrix);
          }
  
          if (projectionMatrix)
          {
              this.multiplyLocal(projectionMatrix);
          }
  
          return this;
      },
  
      /**
       * Multiplies this Matrix4 by the given `src` Matrix4 and stores the results in the `out` Matrix4.
       *
       * @method Phaser.Math.Matrix4#multiplyToMat4
       * @since 3.50.0
       *
       * @param {Phaser.Math.Matrix4} src - The Matrix4 to multiply with this one.
       * @param {Phaser.Math.Matrix4} out - The receiving Matrix.
       *
       * @return {Phaser.Math.Matrix4} This `out` Matrix4.
       */
      multiplyToMat4: function (src, out)
      {
          var a = this.val;
          var b = src.val;
  
          var a00 = a[0];
          var a01 = a[1];
          var a02 = a[2];
          var a03 = a[3];
          var a10 = a[4];
          var a11 = a[5];
          var a12 = a[6];
          var a13 = a[7];
          var a20 = a[8];
          var a21 = a[9];
          var a22 = a[10];
          var a23 = a[11];
          var a30 = a[12];
          var a31 = a[13];
          var a32 = a[14];
          var a33 = a[15];
  
          var b00 = b[0];
          var b01 = b[1];
          var b02 = b[2];
          var b03 = b[3];
          var b10 = b[4];
          var b11 = b[5];
          var b12 = b[6];
          var b13 = b[7];
          var b20 = b[8];
          var b21 = b[9];
          var b22 = b[10];
          var b23 = b[11];
          var b30 = b[12];
          var b31 = b[13];
          var b32 = b[14];
          var b33 = b[15];
  
          return out.setValues(
              b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30,
              b01 * a01 + b01 * a11 + b02 * a21 + b03 * a31,
              b02 * a02 + b01 * a12 + b02 * a22 + b03 * a32,
              b03 * a03 + b01 * a13 + b02 * a23 + b03 * a33,
  
              b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30,
              b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31,
              b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32,
              b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33,
  
              b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30,
              b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31,
              b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32,
              b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33,
  
              b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30,
              b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31,
              b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32,
              b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33
          );
      },
  
      /**
       * Takes the rotation and position vectors and builds this Matrix4 from them.
       *
       * @method Phaser.Math.Matrix4#fromRotationXYTranslation
       * @since 3.50.0
       *
       * @param {Phaser.Math.Vector3} rotation - The rotation vector.
       * @param {Phaser.Math.Vector3} position - The position vector.
       * @param {boolean} translateFirst - Should the operation translate then rotate (`true`), or rotate then translate? (`false`)
       *
       * @return {this} This Matrix4.
       */
      fromRotationXYTranslation: function (rotation, position, translateFirst)
      {
          var x = position.x;
          var y = position.y;
          var z = position.z;
  
          var sx = Math.sin(rotation.x);
          var cx = Math.cos(rotation.x);
  
          var sy = Math.sin(rotation.y);
          var cy = Math.cos(rotation.y);
  
          var a30 = x;
          var a31 = y;
          var a32 = z;
  
          //  Rotate X
  
          var b21 = -sx;
  
          //  Rotate Y
  
          var c01 = 0 - b21 * sy;
  
          var c02 = 0 - cx * sy;
  
          var c21 = b21 * cy;
  
          var c22 = cx * cy;
  
          //  Translate
          if (!translateFirst)
          {
              // a30 = cy * x + 0 * y + sy * z;
              a30 = cy * x + sy * z;
              a31 = c01 * x + cx * y + c21 * z;
              a32 = c02 * x + sx * y + c22 * z;
          }
  
          return this.setValues(
              cy,
              c01,
              c02,
              0,
              0,
              cx,
              sx,
              0,
              sy,
              c21,
              c22,
              0,
              a30,
              a31,
              a32,
              1
          );
      },
  
      /**
       * Returns the maximum axis scale from this Matrix4.
       *
       * @method Phaser.Math.Matrix4#getMaxScaleOnAxis
       * @since 3.50.0
       *
       * @return {number} The maximum axis scale.
       */
      getMaxScaleOnAxis: function ()
      {
          var m = this.val;
  
          var scaleXSq = m[0] * m[0] + m[1] * m[1] + m[2] * m[2];
          var scaleYSq = m[4] * m[4] + m[5] * m[5] + m[6] * m[6];
          var scaleZSq = m[8] * m[8] + m[9] * m[9] + m[10] * m[10];
  
          return Math.sqrt(Math.max(scaleXSq, scaleYSq, scaleZSq));
      }
  
  });
  
  /**
   * @ignore
   */
  var _tempMat1 = new Matrix4();
  
  /**
   * @ignore
   */
  var _tempMat2 = new Matrix4();
  
  /**
   * @ignore
   */
  var _x = new Vector3();
  
  /**
   * @ignore
   */
  var _y = new Vector3();
  
  /**
   * @ignore
   */
  var _z = new Vector3();
  
  module.exports = Matrix4;
  