text: /**
   * @author       Richard Davey <rich@photonstorm.com>
   * @copyright    2019 Photon Storm Ltd.
   * @license      {@link https://opensource.org/licenses/MIT|MIT License}
   */
  
  /**
   * Implements a model view projection matrices.
   * Pipelines can implement this for doing 2D and 3D rendering.
   *
   * @namespace Phaser.Renderer.WebGL.Pipelines.ModelViewProjection
   * @since 3.0.0
   */
  var ModelViewProjection = {
  
      /**
       * Dirty flag for checking if model matrix needs to be updated on GPU.
       * 
       * @name Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#modelMatrixDirty
       * @type {boolean}
       * @since 3.0.0
       */
      modelMatrixDirty: false,
  
      /**
       * Dirty flag for checking if view matrix needs to be updated on GPU.
       * 
       * @name Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#viewMatrixDirty
       * @type {boolean}
       * @since 3.0.0
       */
      viewMatrixDirty: false,
  
      /**
       * Dirty flag for checking if projection matrix needs to be updated on GPU.
       * 
       * @name Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#projectionMatrixDirty
       * @type {boolean}
       * @since 3.0.0
       */
      projectionMatrixDirty: false,
  
      /**
       * Model matrix
       * 
       * @name Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#modelMatrix
       * @type {?Float32Array}
       * @since 3.0.0
       */
      modelMatrix: null,
  
      /**
       * View matrix
       * 
       * @name Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#viewMatrix
       * @type {?Float32Array}
       * @since 3.0.0
       */
      viewMatrix: null,
  
      /**
       * Projection matrix
       * 
       * @name Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#projectionMatrix
       * @type {?Float32Array}
       * @since 3.0.0
       */
      projectionMatrix: null,
  
      /**
       * Initializes MVP matrices with an identity matrix
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#mvpInit
       * @since 3.0.0
       */
      mvpInit: function ()
      {
          this.modelMatrixDirty = true;
          this.viewMatrixDirty = true;
          this.projectionMatrixDirty = true;
          
          this.modelMatrix = new Float32Array([
              1, 0, 0, 0,
              0, 1, 0, 0,
              0, 0, 1, 0,
              0, 0, 0, 1
          ]);
          
          this.viewMatrix = new Float32Array([
              1, 0, 0, 0,
              0, 1, 0, 0,
              0, 0, 1, 0,
              0, 0, 0, 1
          ]);
          
          this.projectionMatrix = new Float32Array([
              1, 0, 0, 0,
              0, 1, 0, 0,
              0, 0, 1, 0,
              0, 0, 0, 1
          ]);
          
          return this;
      },
  
      /**
       * If dirty flags are set then the matrices are uploaded to the GPU.
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#mvpUpdate
       * @since 3.0.0
       */
      mvpUpdate: function ()
      {
          var program = this.program;
  
          if (this.modelMatrixDirty)
          {
              this.renderer.setMatrix4(program, 'uModelMatrix', false, this.modelMatrix);
              this.modelMatrixDirty = false;
          }
          
          if (this.viewMatrixDirty)
          {
              this.renderer.setMatrix4(program, 'uViewMatrix', false, this.viewMatrix);
              this.viewMatrixDirty = false;
          }
  
          if (this.projectionMatrixDirty)
          {
              this.renderer.setMatrix4(program, 'uProjectionMatrix', false, this.projectionMatrix);
              this.projectionMatrixDirty = false;
          }
  
          return this;
      },
  
      /**
       * Loads an identity matrix to the model matrix
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#modelIdentity
       * @since 3.0.0
       */
      modelIdentity: function ()
      {
          var modelMatrix = this.modelMatrix;
          
          modelMatrix[0] = 1;
          modelMatrix[1] = 0;
          modelMatrix[2] = 0;
          modelMatrix[3] = 0;
          modelMatrix[4] = 0;
          modelMatrix[5] = 1;
          modelMatrix[6] = 0;
          modelMatrix[7] = 0;
          modelMatrix[8] = 0;
          modelMatrix[9] = 0;
          modelMatrix[10] = 1;
          modelMatrix[11] = 0;
          modelMatrix[12] = 0;
          modelMatrix[13] = 0;
          modelMatrix[14] = 0;
          modelMatrix[15] = 1;
  
          this.modelMatrixDirty = true;
          
          return this;
      },
  
      /**
       * Scale model matrix
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#modelScale
       * @since 3.0.0
       *
       * @param {number} x - The x component.
       * @param {number} y - The y component.
       * @param {number} z - The z component.
       *
       * @return {this} This Model View Projection.
       */
      modelScale: function (x, y, z)
      {
          var modelMatrix = this.modelMatrix;
  
          modelMatrix[0] = modelMatrix[0] * x;
          modelMatrix[1] = modelMatrix[1] * x;
          modelMatrix[2] = modelMatrix[2] * x;
          modelMatrix[3] = modelMatrix[3] * x;
          modelMatrix[4] = modelMatrix[4] * y;
          modelMatrix[5] = modelMatrix[5] * y;
          modelMatrix[6] = modelMatrix[6] * y;
          modelMatrix[7] = modelMatrix[7] * y;
          modelMatrix[8] = modelMatrix[8] * z;
          modelMatrix[9] = modelMatrix[9] * z;
          modelMatrix[10] = modelMatrix[10] * z;
          modelMatrix[11] = modelMatrix[11] * z;
      
          this.modelMatrixDirty = true;
  
          return this;
      },
  
      /**
       * Translate model matrix
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#modelTranslate
       * @since 3.0.0
       *
       * @param {number} x - The x component.
       * @param {number} y - The y component.
       * @param {number} z - The z component.
       *
       * @return {this} This Model View Projection.
       */
      modelTranslate: function (x, y, z)
      {
          var modelMatrix = this.modelMatrix;
  
          modelMatrix[12] = modelMatrix[0] * x + modelMatrix[4] * y + modelMatrix[8] * z + modelMatrix[12];
          modelMatrix[13] = modelMatrix[1] * x + modelMatrix[5] * y + modelMatrix[9] * z + modelMatrix[13];
          modelMatrix[14] = modelMatrix[2] * x + modelMatrix[6] * y + modelMatrix[10] * z + modelMatrix[14];
          modelMatrix[15] = modelMatrix[3] * x + modelMatrix[7] * y + modelMatrix[11] * z + modelMatrix[15];
  
          this.modelMatrixDirty = true;
  
          return this;
      },
  
      /**
       * Rotates the model matrix in the X axis.
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#modelRotateX
       * @since 3.0.0
       *
       * @param {number} radians - The amount to rotate by.
       *
       * @return {this} This Model View Projection.
       */
      modelRotateX: function (radians)
      {
          var modelMatrix = this.modelMatrix;
          var s = Math.sin(radians);
          var c = Math.cos(radians);
          var a10 = modelMatrix[4];
          var a11 = modelMatrix[5];
          var a12 = modelMatrix[6];
          var a13 = modelMatrix[7];
          var a20 = modelMatrix[8];
          var a21 = modelMatrix[9];
          var a22 = modelMatrix[10];
          var a23 = modelMatrix[11];
  
          modelMatrix[4] = a10 * c + a20 * s;
          modelMatrix[5] = a11 * c + a21 * s;
          modelMatrix[6] = a12 * c + a22 * s;
          modelMatrix[7] = a13 * c + a23 * s;
          modelMatrix[8] = a20 * c - a10 * s;
          modelMatrix[9] = a21 * c - a11 * s;
          modelMatrix[10] = a22 * c - a12 * s;
          modelMatrix[11] = a23 * c - a13 * s;
  
          this.modelMatrixDirty = true;
  
          return this;
      },
  
      /**
       * Rotates the model matrix in the Y axis.
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#modelRotateY
       * @since 3.0.0
       *
       * @param {number} radians - The amount to rotate by.
       *
       * @return {this} This Model View Projection.
       */
      modelRotateY: function (radians)
      {
          var modelMatrix = this.modelMatrix;
          var s = Math.sin(radians);
          var c = Math.cos(radians);
          var a00 = modelMatrix[0];
          var a01 = modelMatrix[1];
          var a02 = modelMatrix[2];
          var a03 = modelMatrix[3];
          var a20 = modelMatrix[8];
          var a21 = modelMatrix[9];
          var a22 = modelMatrix[10];
          var a23 = modelMatrix[11];
  
          modelMatrix[0] = a00 * c - a20 * s;
          modelMatrix[1] = a01 * c - a21 * s;
          modelMatrix[2] = a02 * c - a22 * s;
          modelMatrix[3] = a03 * c - a23 * s;
          modelMatrix[8] = a00 * s + a20 * c;
          modelMatrix[9] = a01 * s + a21 * c;
          modelMatrix[10] = a02 * s + a22 * c;
          modelMatrix[11] = a03 * s + a23 * c;
  
          this.modelMatrixDirty = true;
          
          return this;
      },
      
      /**
       * Rotates the model matrix in the Z axis.
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#modelRotateZ
       * @since 3.0.0
       *
       * @param {number} radians - The amount to rotate by.
       *
       * @return {this} This Model View Projection.
       */
      modelRotateZ: function (radians)
      {
          var modelMatrix = this.modelMatrix;
          var s = Math.sin(radians);
          var c = Math.cos(radians);
          var a00 = modelMatrix[0];
          var a01 = modelMatrix[1];
          var a02 = modelMatrix[2];
          var a03 = modelMatrix[3];
          var a10 = modelMatrix[4];
          var a11 = modelMatrix[5];
          var a12 = modelMatrix[6];
          var a13 = modelMatrix[7];
  
          modelMatrix[0] = a00 * c + a10 * s;
          modelMatrix[1] = a01 * c + a11 * s;
          modelMatrix[2] = a02 * c + a12 * s;
          modelMatrix[3] = a03 * c + a13 * s;
          modelMatrix[4] = a10 * c - a00 * s;
          modelMatrix[5] = a11 * c - a01 * s;
          modelMatrix[6] = a12 * c - a02 * s;
          modelMatrix[7] = a13 * c - a03 * s;
  
          this.modelMatrixDirty = true;
  
          return this;
      },
  
      /**
       * Loads identity matrix into the view matrix
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#viewIdentity
       * @since 3.0.0
       *
       * @return {this} This Model View Projection.
       */
      viewIdentity: function ()
      {
          var viewMatrix = this.viewMatrix;
          
          viewMatrix[0] = 1;
          viewMatrix[1] = 0;
          viewMatrix[2] = 0;
          viewMatrix[3] = 0;
          viewMatrix[4] = 0;
          viewMatrix[5] = 1;
          viewMatrix[6] = 0;
          viewMatrix[7] = 0;
          viewMatrix[8] = 0;
          viewMatrix[9] = 0;
          viewMatrix[10] = 1;
          viewMatrix[11] = 0;
          viewMatrix[12] = 0;
          viewMatrix[13] = 0;
          viewMatrix[14] = 0;
          viewMatrix[15] = 1;
  
          this.viewMatrixDirty = true;
          
          return this;
      },
      
      /**
       * Scales view matrix
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#viewScale
       * @since 3.0.0
       *
       * @param {number} x - The x component.
       * @param {number} y - The y component.
       * @param {number} z - The z component.
       *
       * @return {this} This Model View Projection.
       */
      viewScale: function (x, y, z)
      {
          var viewMatrix = this.viewMatrix;
  
          viewMatrix[0] = viewMatrix[0] * x;
          viewMatrix[1] = viewMatrix[1] * x;
          viewMatrix[2] = viewMatrix[2] * x;
          viewMatrix[3] = viewMatrix[3] * x;
          viewMatrix[4] = viewMatrix[4] * y;
          viewMatrix[5] = viewMatrix[5] * y;
          viewMatrix[6] = viewMatrix[6] * y;
          viewMatrix[7] = viewMatrix[7] * y;
          viewMatrix[8] = viewMatrix[8] * z;
          viewMatrix[9] = viewMatrix[9] * z;
          viewMatrix[10] = viewMatrix[10] * z;
          viewMatrix[11] = viewMatrix[11] * z;
      
          this.viewMatrixDirty = true;
  
          return this;
      },
  
      /**
       * Translates view matrix
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#viewTranslate
       * @since 3.0.0
       *
       * @param {number} x - The x component.
       * @param {number} y - The y component.
       * @param {number} z - The z component.
       *
       * @return {this} This Model View Projection.
       */
      viewTranslate: function (x, y, z)
      {
          var viewMatrix = this.viewMatrix;
  
          viewMatrix[12] = viewMatrix[0] * x + viewMatrix[4] * y + viewMatrix[8] * z + viewMatrix[12];
          viewMatrix[13] = viewMatrix[1] * x + viewMatrix[5] * y + viewMatrix[9] * z + viewMatrix[13];
          viewMatrix[14] = viewMatrix[2] * x + viewMatrix[6] * y + viewMatrix[10] * z + viewMatrix[14];
          viewMatrix[15] = viewMatrix[3] * x + viewMatrix[7] * y + viewMatrix[11] * z + viewMatrix[15];
  
          this.viewMatrixDirty = true;
  
          return this;
      },
      
      /**
       * Rotates view matrix in the X axis.
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#viewRotateX
       * @since 3.0.0
       *
       * @param {number} radians - The amount to rotate by.
       *
       * @return {this} This Model View Projection.
       */
      viewRotateX: function (radians)
      {
          var viewMatrix = this.viewMatrix;
          var s = Math.sin(radians);
          var c = Math.cos(radians);
          var a10 = viewMatrix[4];
          var a11 = viewMatrix[5];
          var a12 = viewMatrix[6];
          var a13 = viewMatrix[7];
          var a20 = viewMatrix[8];
          var a21 = viewMatrix[9];
          var a22 = viewMatrix[10];
          var a23 = viewMatrix[11];
  
          viewMatrix[4] = a10 * c + a20 * s;
          viewMatrix[5] = a11 * c + a21 * s;
          viewMatrix[6] = a12 * c + a22 * s;
          viewMatrix[7] = a13 * c + a23 * s;
          viewMatrix[8] = a20 * c - a10 * s;
          viewMatrix[9] = a21 * c - a11 * s;
          viewMatrix[10] = a22 * c - a12 * s;
          viewMatrix[11] = a23 * c - a13 * s;
  
          this.viewMatrixDirty = true;
  
          return this;
      },
      
      /**
       * Rotates view matrix in the Y axis.
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#viewRotateY
       * @since 3.0.0
       *
       * @param {number} radians - The amount to rotate by.
       *
       * @return {this} This Model View Projection.
       */
      viewRotateY: function (radians)
      {
          var viewMatrix = this.viewMatrix;
          var s = Math.sin(radians);
          var c = Math.cos(radians);
          var a00 = viewMatrix[0];
          var a01 = viewMatrix[1];
          var a02 = viewMatrix[2];
          var a03 = viewMatrix[3];
          var a20 = viewMatrix[8];
          var a21 = viewMatrix[9];
          var a22 = viewMatrix[10];
          var a23 = viewMatrix[11];
  
          viewMatrix[0] = a00 * c - a20 * s;
          viewMatrix[1] = a01 * c - a21 * s;
          viewMatrix[2] = a02 * c - a22 * s;
          viewMatrix[3] = a03 * c - a23 * s;
          viewMatrix[8] = a00 * s + a20 * c;
          viewMatrix[9] = a01 * s + a21 * c;
          viewMatrix[10] = a02 * s + a22 * c;
          viewMatrix[11] = a03 * s + a23 * c;
  
          this.viewMatrixDirty = true;
          
          return this;
      },
      
      /**
       * Rotates view matrix in the Z axis.
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#viewRotateZ
       * @since 3.0.0
       *
       * @param {number} radians - The amount to rotate by.
       *
       * @return {this} This Model View Projection.
       */
      viewRotateZ: function (radians)
      {
          var viewMatrix = this.viewMatrix;
          var s = Math.sin(radians);
          var c = Math.cos(radians);
          var a00 = viewMatrix[0];
          var a01 = viewMatrix[1];
          var a02 = viewMatrix[2];
          var a03 = viewMatrix[3];
          var a10 = viewMatrix[4];
          var a11 = viewMatrix[5];
          var a12 = viewMatrix[6];
          var a13 = viewMatrix[7];
  
          viewMatrix[0] = a00 * c + a10 * s;
          viewMatrix[1] = a01 * c + a11 * s;
          viewMatrix[2] = a02 * c + a12 * s;
          viewMatrix[3] = a03 * c + a13 * s;
          viewMatrix[4] = a10 * c - a00 * s;
          viewMatrix[5] = a11 * c - a01 * s;
          viewMatrix[6] = a12 * c - a02 * s;
          viewMatrix[7] = a13 * c - a03 * s;
  
          this.viewMatrixDirty = true;
  
          return this;
      },
  
      /**
       * Loads a 2D view matrix (3x2 matrix) into a 4x4 view matrix 
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#viewLoad2D
       * @since 3.0.0
       *
       * @param {Float32Array} matrix2D - The Matrix2D.
       *
       * @return {this} This Model View Projection.
       */
      viewLoad2D: function (matrix2D)
      {
          var vm = this.viewMatrix;
  
          vm[0] = matrix2D[0];
          vm[1] = matrix2D[1];
          vm[2] = 0.0;
          vm[3] = 0.0;
          vm[4] = matrix2D[2];
          vm[5] = matrix2D[3];
          vm[6] = 0.0;
          vm[7] = 0.0;
          vm[8] = matrix2D[4];
          vm[9] = matrix2D[5];
          vm[10] = 1.0;
          vm[11] = 0.0;
          vm[12] = 0.0;
          vm[13] = 0.0;
          vm[14] = 0.0;
          vm[15] = 1.0;
  
          this.viewMatrixDirty = true;
  
          return this;
      },
  
  
      /**
       * Copies a 4x4 matrix into the view matrix
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#viewLoad
       * @since 3.0.0
       *
       * @param {Float32Array} matrix - The Matrix2D.
       *
       * @return {this} This Model View Projection.
       */
      viewLoad: function (matrix)
      {
          var vm = this.viewMatrix;
  
          vm[0] = matrix[0];
          vm[1] = matrix[1];
          vm[2] = matrix[2];
          vm[3] = matrix[3];
          vm[4] = matrix[4];
          vm[5] = matrix[5];
          vm[6] = matrix[6];
          vm[7] = matrix[7];
          vm[8] = matrix[8];
          vm[9] = matrix[9];
          vm[10] = matrix[10];
          vm[11] = matrix[11];
          vm[12] = matrix[12];
          vm[13] = matrix[13];
          vm[14] = matrix[14];
          vm[15] = matrix[15];
  
          this.viewMatrixDirty = true;
  
          return this;
      },
      
      /**
       * Loads identity matrix into the projection matrix.
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#projIdentity
       * @since 3.0.0
       *
       * @return {this} This Model View Projection.
       */
      projIdentity: function ()
      {
          var projectionMatrix = this.projectionMatrix;
          
          projectionMatrix[0] = 1;
          projectionMatrix[1] = 0;
          projectionMatrix[2] = 0;
          projectionMatrix[3] = 0;
          projectionMatrix[4] = 0;
          projectionMatrix[5] = 1;
          projectionMatrix[6] = 0;
          projectionMatrix[7] = 0;
          projectionMatrix[8] = 0;
          projectionMatrix[9] = 0;
          projectionMatrix[10] = 1;
          projectionMatrix[11] = 0;
          projectionMatrix[12] = 0;
          projectionMatrix[13] = 0;
          projectionMatrix[14] = 0;
          projectionMatrix[15] = 1;
  
          this.projectionMatrixDirty = true;
  
          return this;
      },
  
      /**
       * Sets up an orthographic projection matrix
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#projOrtho
       * @since 3.0.0
       *
       * @param {number} left - The left value.
       * @param {number} right - The right value.
       * @param {number} bottom - The bottom value.
       * @param {number} top - The top value.
       * @param {number} near - The near value.
       * @param {number} far - The far value.
       *
       * @return {this} This Model View Projection.
       */
      projOrtho: function (left, right, bottom, top, near, far)
      {
          var projectionMatrix = this.projectionMatrix;
          var leftRight = 1.0 / (left - right);
          var bottomTop = 1.0 / (bottom - top);
          var nearFar = 1.0 / (near - far);
  
          projectionMatrix[0] = -2.0 * leftRight;
          projectionMatrix[1] = 0.0;
          projectionMatrix[2] = 0.0;
          projectionMatrix[3] = 0.0;
          projectionMatrix[4] = 0.0;
          projectionMatrix[5] = -2.0 * bottomTop;
          projectionMatrix[6] = 0.0;
          projectionMatrix[7] = 0.0;
          projectionMatrix[8] = 0.0;
          projectionMatrix[9] = 0.0;
          projectionMatrix[10] = 2.0 * nearFar;
          projectionMatrix[11] = 0.0;
          projectionMatrix[12] = (left + right) * leftRight;
          projectionMatrix[13] = (top + bottom) * bottomTop;
          projectionMatrix[14] = (far + near) * nearFar;
          projectionMatrix[15] = 1.0;
  
          this.projectionMatrixDirty = true;
  
          return this;
      },
      
      /**
       * Sets up a perspective projection matrix
       * 
       * @method Phaser.Renderer.WebGL.Pipelines.ModelViewProjection#projPersp
       * @since 3.0.0
       *
       * @param {number} fovY - The fov value.
       * @param {number} aspectRatio - The aspectRatio value.
       * @param {number} near - The near value.
       * @param {number} far - The far value.
       *
       * @return {this} This Model View Projection.
       */
      projPersp: function (fovY, aspectRatio, near, far)
      {
          var projectionMatrix = this.projectionMatrix;
          var fov = 1.0 / Math.tan(fovY / 2.0);
          var nearFar = 1.0 / (near - far);
          
          projectionMatrix[0] = fov / aspectRatio;
          projectionMatrix[1] = 0.0;
          projectionMatrix[2] = 0.0;
          projectionMatrix[3] = 0.0;
          projectionMatrix[4] = 0.0;
          projectionMatrix[5] = fov;
          projectionMatrix[6] = 0.0;
          projectionMatrix[7] = 0.0;
          projectionMatrix[8] = 0.0;
          projectionMatrix[9] = 0.0;
          projectionMatrix[10] = (far + near) * nearFar;
          projectionMatrix[11] = -1.0;
          projectionMatrix[12] = 0.0;
          projectionMatrix[13] = 0.0;
          projectionMatrix[14] = (2.0 * far * near) * nearFar;
          projectionMatrix[15] = 0.0;
          
          this.projectionMatrixDirty = true;
  
          return this;
      }
  };
  
  module.exports = ModelViewProjection;
  