<!--
Copyright (c) 2019 The Khronos Group Inc.
Use of this source code is governed by an MIT-style license that can be
found in the LICENSE.txt file.
-->

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebGL uniformMatrix Conformance Tests</title>
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
<script src="../../js/js-test-pre.js"></script>
<script src="../../js/webgl-test-utils.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<canvas id="example" width="2" height="2"> </canvas>

<script id="vshader" type="x-shader/x-vertex">
uniform mat2 world2x2;
uniform mat3 world3x3;
uniform mat4 world4x4;
void main() {
  gl_Position.x += world2x2[0][0];
  gl_Position.x += world3x3[0][0];
  gl_Position.x += world4x4[0][0];
}
</script>

<script id="fshader" type="x-shader/x-fragment">
void main() {}
</script>

<script id="vshader300" type="x-shader/x-vertex">
#version 300 es
uniform mat2   world2x2;
uniform mat2x3 world2x3;
uniform mat2x4 world2x4;
uniform mat3x2 world3x2;
uniform mat3   world3x3;
uniform mat3x4 world3x4;
uniform mat4x2 world4x2;
uniform mat4x3 world4x3;
uniform mat4   world4x4;
void main() {
  gl_Position.x += world2x2[0][0];
  gl_Position.x += world2x3[0][0];
  gl_Position.x += world2x4[0][0];
  gl_Position.x += world3x2[0][0];
  gl_Position.x += world3x3[0][0];
  gl_Position.x += world3x4[0][0];
  gl_Position.x += world4x2[0][0];
  gl_Position.x += world4x3[0][0];
  gl_Position.x += world4x4[0][0];
}
</script>

<script id="fshader300" type="x-shader/x-fragment">
#version 300 es
void main() {}
</script>

<script>
"use strict";
description("This test ensures WebGL implementations handle uniformMatrix in a OpenGL ES 2.0 spec compliant way");

debug("");
debug("Checking gl.uniformMatrix.");

var wtu = WebGLTestUtils;
var gl = wtu.create3DContext("example");
var contextVersion = wtu.getDefault3DContextVersion();

let shaders = ["vshader", "fshader"];
const dims = [
  [2, 2, 'uniformMatrix2fv'],
  [3, 3, 'uniformMatrix3fv'],
  [4, 4, 'uniformMatrix4fv'],
];

if (contextVersion >= 2) {
  shaders = ["vshader300", "fshader300"];
  dims.push(
    [2, 3, 'uniformMatrix2x3fv'],
    [2, 4, 'uniformMatrix2x4fv'],
    [3, 2, 'uniformMatrix3x2fv'],
    [3, 4, 'uniformMatrix3x4fv'],
    [4, 2, 'uniformMatrix4x2fv'],
    [4, 3, 'uniformMatrix4x3fv']
  );
}

const program = wtu.setupProgram(gl, shaders);
let loc;

for (const [A, B, name] of dims) {
  loc = gl.getUniformLocation(program, `world${A}x${B}`);
  if (!loc) throw 'missing loc';

  const mat = [];
  for (let a = 0; a < A; ++a) {
    for (let b = 0; b < B; ++b) {
      mat.push((a == b) ? 1 : 0);
    }
  }
  const matLess = mat.slice(0, mat.length-2);
  const matMore = mat.concat([1]);

  gl[name](loc, false, matLess);
  wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "should fail with insufficient array size for " + name);
  gl[name](loc, false, mat);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should succeed with correct array size for " + name);
  gl[name](loc, false, matMore);
  wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "should fail with more than 1 array size for " + name);

  const validDatas = [
    `new Float32Array(${mat.length})`,
    `new Float32Array(new ArrayBuffer(4*${mat.length}))`,
  ];
  if (window.SharedArrayBuffer) {
    validDatas.push(
      `new Float32Array(new SharedArrayBuffer(4*${mat.length}))`
    );
  }
  for (const x of validDatas) {
    shouldNotThrow(`gl.${name}(loc, false, ${x});`);
  }

  gl[name](loc, false, mat);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "can call " + name + "with transpose = false");
  if (contextVersion <= 1) {
    gl[name](loc, true, mat);
    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, name + " should return INVALID_VALUE with transpose = true");
  } else {
    gl[name](loc, true, mat);
    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "can call " + name + "with transpose = true");
  }
}

debug("");
var successfullyParsed = true;

</script>
<script src="../../js/js-test-post.js"></script>

</body>
</html>
