<!--
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 short-circuit evaluation</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>

<!-------------------------------------
  WebGL Shaders
---------------------------------------->
<!-- Pass through Shaders -->
<script id="vshader0" type="x-shader/x-vertex">
/* PASS-THROUGH VERTEX SHADER */
attribute vec4 vPosition;

void main()
{
    gl_Position = vPosition;
}
</script>

<script id="fshader0" type="x-shader/x-fragment">
/* PASS-THROUGH FRAGMENT SHADER */
precision mediump float;
varying vec4 vPassThrough;

void main()
{
    gl_FragColor = vPassThrough;
}
</script>

<!-- basic conditonal short circuit Shaders -->
<script id="vshader1" type="x-shader/x-vertex">
attribute vec4 vPosition;
varying vec4 vPassThrough;

void main()
{
    int x = 1;
    $(variables)

    if ($(condition))
    { /*do nothing*/ }

    /* if x was unmodified return green, else return red */
    vPassThrough = (x == 1) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
    gl_Position = vPosition;
}
</script>

<script id="fshader1" type="x-shader/x-fragment">
precision mediump float;

void main()
{
    int x = 1;
    $(variables)

    if ($(condition))
    { /*do nothing*/ }

    gl_FragColor = (x == 1) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
}
</script>

<!-- Main body of the Webgl program -->
<script>
"use strict";
description();

var wtu = WebGLTestUtils;
var gl = wtu.create3DContext();

wtu.setupUnitQuad(gl, [0, 1]);

var shaderTemplates = [
    { vs: "vshader1", fs: "fshader0" }, // basic vertex short-circuit test
    { vs: "vshader0", fs: "fshader1" }, // basic fragment short-circuit test
];

/* replace the names of the shaders in the tempate variables with
 * the shaders themselves */
for (var ii = 0; ii < shaderTemplates.length; ++ii) {
    var template = shaderTemplates[ii];
    template.vs = wtu.getScript(template.vs);
    template.fs = wtu.getScript(template.fs);
}

/* define the conditon that will be used in the shaders. If additional
 * variables are needed that are not present i the shader they my be
 * defined in the variables variable */
var tests = [
    { condition: "true || (x = 0) == 1", variables: "" }, /* test basic 'or' short circuit */
    { condition: "false && (x = 0) == 1", variables: "" }, /* test basic 'and' short circuit */
    { condition: "(j == 3 && j == k) || (j > (x = 0))", variables: "int j = 3;\nint k = 3;" }, /* test basic 'or' short circuit with actual condition */
    { condition: "(j == 3 && j == k) && (j > (x = 0))", variables: "int j = 3;\nint k = 4;" }, /* test basic 'and' short circuit with actual condition */
    { condition: "(j + 3 > k && ((j < 10) || (x + 5 > j + (x = 0))) || ( x = 0 ) == 7)", variables: "int j = 5;\nint k = 3;" }, /* complex test */
    { condition: "j + 1 == 6 ? x == 1 || j > (x = 0) : (x = 0) == 1 && (x = 0) <= 1", variables: "int j = 5;" }, /* nested with ternary operator */
    { condition: "true && (true || (x = 0) == 1)", variables: "" }, /* test unfold short circuit update order correctness */
];

function testShortCircuit(test) {
    debug("");
    debug("testing short circuit condition: " + test.condition);

    /* Setting clear color to blue */
    gl.clearColor(0.0, 0.0, 1.0, 1.0);

    for (var ii = 0; ii < shaderTemplates.length; ++ii) {

        /* clear the screen so that subsequent tests don't conflict */
        gl.clear(gl.COLOR_BUFFER_BIT);
        var template = shaderTemplates[ii];

        var vs = wtu.replaceParams(template.vs, test);
        var fs = wtu.replaceParams(template.fs, test);

        var program = wtu.setupProgram(gl, [vs, fs], ['vPosition'], undefined, true);

        wtu.clearAndDrawUnitQuad(gl);
        wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green", 0);

        gl.deleteProgram(program);

        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no GL errors");
    }
}

var testNdx = 0;
function runNextTest() {
    testShortCircuit(tests[testNdx++]);
    if (testNdx >= tests.length) {
        finishTest();
    } else {
        setTimeout(runNextTest, 0);
    }
}

runNextTest();
</script>
</body>
</html>
