﻿<!--

/*
** Copyright (c) 2012 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/

-->

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebGL WebGL_debug_shaders Conformance Tests</title>
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
<script src="../../resources/desktop-gl-constants.js" type="text/javascript"></script>
<script src="../../resources/js-test-pre.js"></script>
<script src="../resources/webgl-test.js"></script>
<script src="../resources/webgl-test-utils.js"></script>
</head>
<body>
<div id="description"></div>
<canvas id="canvas" style="width: 1px; height: 1px;"> </canvas>
<div id="console"></div>
<!-- Shaders for testing standard derivatives -->

<script>
"use strict";
description("This test verifies the functionality of the WEBGL_debug_shaders extension, if it is available.");

debug("");

var wtu = WebGLTestUtils;
var gl = wtu.create3DContext("canvas");
var ext = null;
var shader = null;
var program = null;
var info = null;
var translatedSource;
var newTranslatedSource;

if (!gl) {
    testFailed("WebGL context does not exist");
} else {
    testPassed("WebGL context exists");

    // Query the extension and store globally so shouldBe can access it
    ext = gl.getExtension("WEBGL_debug_shaders");
    if (!ext) {
        testPassed("No WEBGL_debug_shaders support -- this is legal");

        runSupportedTest(false);
    } else {
        testPassed("Successfully enabled WEBGL_debug_shaders extension");

        runSupportedTest(true);
        runTestEnabled();
    }
}

function runSupportedTest(extensionEnabled) {
    var supported = gl.getSupportedExtensions();
    if (supported.indexOf("WEBGL_debug_shaders") >= 0) {
        if (extensionEnabled) {
            testPassed("WEBGL_debug_shaders listed as supported and getExtension succeeded");
        } else {
            testFailed("WEBGL_debug_shaders listed as supported but getExtension failed");
        }
    } else {
        if (extensionEnabled) {
            testFailed("WEBGL_debug_shaders not listed as supported but getExtension succeeded");
        } else {
            testPassed("WEBGL_debug_shaders not listed as supported and getExtension failed -- this is legal");
        }
    }
}

function runTestEnabled() {
    debug("Testing function with extension enabled");

    var shaderInfos = [
      {
        source: "void main() { gl_Position = vec4(1.0, 0.0, 0.0, 1.0); }",
        type: gl.VERTEX_SHADER
      },
      {
        source: "void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }",
        type: gl.FRAGMENT_SHADER
      }
    ];

    // Do this twice to test for caching issues.
    for (var jj = 0; jj < 2; ++jj) {
        debug("pass:" + (jj + 1));
        program = gl.createProgram();
        for (var ii = 0; ii < shaderInfos.length; ++ii) {
            info = shaderInfos[ii];

            shader = gl.createShader(info.type);

            // if no source has been defined or compileShader() has not been called,
            // getTranslatedShaderSource() should return an empty string.
            shouldBe("ext.getTranslatedShaderSource(shader)", '""');
            gl.shaderSource(shader, info.source);
            shouldBe("ext.getTranslatedShaderSource(shader)", '""');
            gl.compileShader(shader);
            shouldBeTrue("gl.getShaderParameter(shader, gl.COMPILE_STATUS)");
            translatedSource = ext.getTranslatedShaderSource(shader);
            glErrorShouldBe(gl, gl.NO_ERROR, "No gl error should occur");
            if (translatedSource && translatedSource.length > 0) {
                testPassed("Successfully called getTranslatedShaderSource()");
            } else {
                testFailed("Calling getTranslatedShaderSource() failed");
            }
            gl.attachShader(program, shader);
        }
        gl.linkProgram(program);
        shouldBeTrue("gl.getProgramParameter(program, gl.LINK_STATUS)");
    }

    // Test changing the source. Make sure we get the correct source each time.
    debug("test changing source");
    shader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(shader, "void main() { gl_FragColor = vec4(gl_FragCoord.x, 0.0, 0.0, 1.0); }");
    gl.compileShader(shader);
    shouldBeTrue("gl.getShaderParameter(shader, gl.COMPILE_STATUS)");
    translatedSource = ext.getTranslatedShaderSource(shader);
    shouldBeTrue('translatedSource && translatedSource.indexOf("gl_FragCoord") >= 0');
    // change the source but don't compile.
    gl.shaderSource(shader, "void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }");
    // the source should NOT change. It should be the same as the old source.
    newTranslatedSource = ext.getTranslatedShaderSource(shader);
    shouldBe('newTranslatedSource', 'translatedSource');
    // now compile.
    gl.compileShader(shader);
    shouldBeTrue("gl.getShaderParameter(shader, gl.COMPILE_STATUS)");
    // the source should have change.
    newTranslatedSource = ext.getTranslatedShaderSource(shader);
    shouldNotBe('newTranslatedSource', 'translatedSource');
}

debug("");
var successfullyParsed = true;
</script>
<script src="../../resources/js-test-post.js"></script>

</body>
</html>
