text: import * as mat4 from 'gl-matrix/mat4';
  import * as vec3 from 'gl-matrix/vec3';
  import * as vec4 from 'gl-matrix/vec4';
  
  /**
   * Multiplies a vec4 with a matrix
   *
   * @category Math
   * @param {vec4} out the receiving vector
   * @param {vec4} a the first operand
   * @param {mat4} m matrix to multiply with (in column major order)
   * @return {vec4} out
   */
  export const multiplyWithMat4 = (a, m) => [
      m[0] * a[0] + m[4] * a[1] + m[8] * a[2] + m[12] * a[3],
      m[1] * a[0] + m[5] * a[1] + m[9] * a[2] + m[13] * a[3],
      m[2] * a[0] + m[6] * a[1] + m[10] * a[2] + m[14] * a[3],
      m[3] * a[0] + m[7] * a[1] + m[11] * a[2] + m[15] * a[3],
  ];
  
  /**
   * Project a point from 3D space to 2D space
   *
   * @category Math
   * @param {vec2} source 2D point on screen
   * @param {mat4} model Camera view matrix
   * @param {mat4} projection Camera projection matrix
   * @return {vec4} viewport Viewport
   */
  export const project = (source, model, projection, viewport) => {
      let tmp = vec4.fromValues(source[0], source[1], source[2], 1.0);
      const tmp2 = multiplyWithMat4(tmp, model);
      tmp = multiplyWithMat4(tmp2, projection);
  
      tmp[0] = (tmp[0] / tmp[3]) * 0.5 + 0.5;
      tmp[1] = (tmp[1] / tmp[3]) * 0.5 + 0.5;
      tmp[2] = (tmp[2] / tmp[3]) * 0.5 + 0.5;
  
      tmp[0] = tmp[0] * viewport[2] + viewport[0];
      tmp[1] = tmp[1] * viewport[3] + viewport[1];
  
      return vec3.fromValues(tmp[0], tmp[1], tmp[2]);
  };
  
  /**
   * Un-project a point from 2D space to 3D space
   *
   * Z value must have one of this two values:
   * - 0 for near plane
   * - 1 for far plane
   *
   * @category Math
   * @param {vec3} source 2D point on screen
   * @param {mat4} model Camera view matrix
   * @param {mat4} projection Camera projection matrix
   * @return {vec4} viewport Viewport
   */
  export const unproject = (source, model, projection, viewport) => {
      // Calculate using viewport
      const tmp = vec4.fromValues(source[0], source[1], source[2], 1.0);
      tmp[0] = (tmp[0] - viewport[0]) / viewport[2];
      tmp[1] = (tmp[1] - viewport[1]) / viewport[3];
      tmp[0] = tmp[0] * 2 - 1;
      tmp[1] = tmp[1] * 2 - 1;
      tmp[2] = tmp[2] * 2 - 1;
  
      // Compute inverse matrix
      const matrix = mat4.create();
      mat4.multiply(matrix, projection, model);
      mat4.invert(matrix, matrix);
  
      // Apply inverse matrix
      let obj = mat4.create();
      obj = multiplyWithMat4(tmp, matrix);
      obj[0] /= obj[3];
      obj[1] /= obj[3];
      obj[2] /= obj[3];
  
      return vec3.fromValues(obj[0], obj[1], obj[2]);
  };
  